2D RMQ Range Tree - c++

Hi I'm trying to implement a 2D range tree for rmq-ing, here's my code, i think it's not efficient enough, is there anything i can do for optimation.
ls contain list of y sorted on every node
rt contain a segment tree
p.fi.fi contain x coordinate
p.fi.se contain y coordinate
p.se contain id of the point
loc contain x node and y node for each id
vector<pii> ls[400005];
vector<int> rt[400005];
pair<pii,int> p[100005];
vector<pii> loc[100005];
inline void merge(int id,vector<pii> &res,vector<pii> &a,vector<pii> &b)
{
int la = 0;
int lb = 0;
int sa = SIZE(a);
int sb = SIZE(b);
while(la < sa || lb < sb)
{
if (la >= sa) {res.pb(b[lb]);loc[b[lb].se].pb(mp(id,SIZE(res)-1));lb++;}
else if (lb >= sb) {res.pb(a[la]);loc[a[la].se].pb(mp(id,SIZE(res)-1));la++;}
else
{
if (a[la] < b[lb]) {res.pb(a[la]);loc[a[la].se].pb(mp(id,SIZE(res)-1));la++;}
else {res.pb(b[lb]);loc[b[lb].se].pb(mp(id,SIZE(res)-1));lb++;}
}
}
}
inline void build_x(int n,int l,int r)
{
if (l == r)
{
ls[n].clear();
ls[n].pb(mp(p[l].fi.se,p[l].se));
rt[n].assign(SIZE(ls[n])<<2,0);
loc[p[l].se].pb(mp(n,0));
return;
}
int m = (l+r)>>1;
build_x((n<<1),l,m);
build_x((n<<1)+1,m+1,r);
ls[n].clear();
merge(n,ls[n],ls[(n<<1)],ls[(n<<1)+1]);
rt[n].assign(SIZE(ls[n])<<2,0);
}
inline int query_y(int nx,int n,int l,int r,int ly,int ry)
{
if (ly > ls[nx][r].fi || ry < ls[nx][l].fi) return 0;
if (ly <= ls[nx][l].fi && ls[nx][r].fi <= ry)
{
return rt[nx][n];
}
int res = 0;
int m = (l+r)>>1;
if (ly <= ls[nx][m].fi) MAX(res,query_y(nx,(n<<1),l,m,ly,min(ls[nx][m].fi,ry)));
if (ls[nx][m+1].fi <= ry) MAX(res,query_y(nx,(n<<1)+1,m+1,r,max(ls[nx][m+1].fi,ly),ry));
return res;
}
inline int query_x(int n,int l,int r,int lx,int rx,int ly,int ry)
{
if (lx > p[r].fi.fi || rx < p[l].fi.fi) return 0;
if (lx <= p[l].fi.fi && p[r].fi.fi <= rx)
{
return query_y(n,1,0,SIZE(ls[n])-1,ly,ry);
}
int res = 0;
int m = (l+r)>>1;
if (lx <= p[m].fi.fi) MAX(res,query_x((n<<1),l,m,lx,min(p[m].fi.fi,rx),ly,ry));
if (p[m+1].fi.fi <= rx) MAX(res,query_x((n<<1)+1,m+1,r,max(p[m+1].fi.fi,lx),rx,ly,ry));
return res;
}
int nx;
inline void update_y(int n,int l,int r,int fy,int v)
{
if (l == r)
{
MAX(rt[nx][n],v);
return;
}
int m = (l+r)>>1;
if (fy <= m) update_y((n<<1),l,m,fy,v);
else update_y((n<<1)+1,m+1,r,fy,v);
rt[nx][n] = max(rt[nx][(n<<1)],rt[nx][(n<<1)+1]);
}
i'm sorry if the code was a mess since it's my first implementation of range tree
My current implementation run for about 4s, but i need it to run less than 3s, here's my full implementation
Thanks :)

Related

time complexity of this algorithm written below

According to my calculations , the time complexity of this algorithm/code is O(logN) as it is an enhancement of binary search, but while submitting the code in leetcode and other platforms , it is said that the time limit is exceeded . they are also expecting the time complexity of this algorithm to be O(logN), so please confirm is the complexity of code written below is O(logN) or is it different from that?
class Solution {
public:
int findLast(vector<int> arr, int n, int x)
{
int l = 0;
int h = n - 1;
int mid;
while (h >= l) {
mid = (l + h) / 2;
if (arr[mid] == x) {
if (arr[mid + 1] != x) {
return mid;
}
else {
l = mid + 1;
}
}
else if (arr[mid] > x) {
h = mid;
}
else if (arr[mid] < x) {
l = mid + 1;
}
}
return -1;
}
int findFirst(vector<int> arr, int n, int x)
{
int l = 0;
int h = n - 1;
int mid;
while (h >= l) {
mid = (l + h) / 2;
if (arr[mid] == x) {
if (arr[mid - 1] != x) {
return mid;
}
else {
h = mid;
}
}
else if (arr[mid] > x) {
h = mid;
}
else if (arr[mid] < x) {
l = mid + 1;
}
}
return -1;
}
vector<int> searchRange(vector<int>& nums, int target)
{
int last = findLast(nums, nums.size(), target);
int first = findFirst(nums, nums.size(), target);
vector<int> v1 = { first, last };
return v1;
}
};
Your code's time complexity is O(∞) because it can perform an infinite loop.
Consider what happens when you run findLast on a one-element vector. You will have h, l, and mid equal to 0. If you enter the arr[mid] > x branch then you run h = mid; which leaves the variables unchanged, and repeats indefinitely.
Besides this, you should take the vector parameter by reference to avoid a copy which would make this a linear runtime.
Your code does not handle some corner cases where the input could be [1,1] and the target is 1. In findLast , the low and high variables would come to 1 and segmentation fault would occur when you check for arr[mid+1]. The same explanation would go for findFirst as well.
Try this and see if it helps:
int findLast(vector<int> arr, int n, int x)
{
int l = 0;
int h = n - 1;
int mid;
while (h > l)
{
mid = (l + h) / 2;
if (arr[mid] == x)
{
if (arr[mid + 1] != x)
{
return mid;
}
else
{
l = mid + 1;
}
}
else if (arr[mid] > x)
{
h = mid;
}
else if (arr[mid] < x)
{
l = mid + 1;
}
}
return arr[l] == x ? l : -1;
}

Finding a path in a maze via backtracking

I want to make a program to find if a path exists from upper right corner to down left corner in a maze via backtracking. The input numbers are n and m which are the dimensions of rectangular maze and a maze, character '.' means a tile which you can go through and character 'x' means a tile which you cant go through. I have wrote the code, its fairly simple but nothing gets displayed whilst it should display "da" (on Serbian "yes") and "ne" (on Serbian "no").
#include <bits/stdc++.h>
using namespace std;
bool maze[20][20]; //defined maze of maximum size 20x20
//checking if a position is viable for moving through
bool Safe(int n, int m, int x, int y)
{
if(x >= 0 && x < n && y >= 0 && y < m)
{
if(maze[x][y] == 1) return true;
}
return false;
}
bool Utility(int n, int m, int x, int y) //main utility function
{
if(x == n - 1 && y == m - 1 && maze[x][y] == 1) // base case, end of maze
{
return true;
}
if(Safe(n, m, x, y))
{
if(Safe(n, m, x + 1, y)) // checking if it is viable to move down
{
if(Utility(n, m, x + 1, y))
{
return true;
}
}
if(Safe(n, m, x, y + 1))
{
if(Utility(n, m, x, y + 1)) // checking if it is viable to move right
{
return true;
}
}
if(Safe(n, m, x - 1, y))
{
if(Utility(n, m, x - 1, y)) // checking if it is viable to move up
{
return true;
}
}
if(Safe(n, m, x, y - 1))
{
if(Utility(n, m, x, y - 1)) // checking if it is viable to move left
{
return true;
}
}
}
return false; // returning false
}
int main()
{
int n, m;
cin >> n >> m; // input dimensions of the maze
for(int i = 0; i < n; i++) // input maze
{
for(int j = 0; j < m; j++)
{
char c;
cin >> c;
if(c == '.') //character '.' means a tile which you can go through
{
maze[i][j] = 1;
}
else //character 'x' means a tile which you cannot go through
{
maze[i][j] = 0;
}
}
}
if(Utility(n, m, 0, 0)) //printing yes or no
{
cout << "da";
}
else
{
cout << "ne";
}
return 0;
}
Sample Input:
8 8
.x.....x
.x.x.x.x
.x.x.x.x
.x.x.x.x
.x.x.x.x
.x.x.x.x
.x.x.x.x
...x.x..
Sample output: da
The problem was that, say if you go from (0, 0) -> (1, 0), then at (1, 0) you can again go back to (0, 0) and this would loop forever. To avoid that, I created a visited array which will have value true if cell (x, y) is already visited, else false.
I have marked where I made the changes with ///////////// change here ///////////// comment
#include <bits/stdc++.h>
using namespace std;
bool maze[20][20]; //defined maze of maximum size 20x20
///////////// change here /////////////
bool visited[20][20];
bool Safe(int n, int m, int x, int y) //checking if a position is viable for moving through
{
if(x >= 0 && x < n && y >= 0 && y < m)
{
if(maze[x][y] == 1) return true;
}
return false;
}
bool Utility(int n, int m, int x, int y) //main utility function
{
if(x == n - 1 && y == m - 1 && maze[x][y] == 1) // base case, end of maze
{
return true;
}
///////////// change here /////////////
if(!visited[x][y] && Safe(n, m, x, y))
{
///////////// change here /////////////
visited[x][y] = true;
if(Safe(n, m, x + 1, y)) // checking if it is viable to move down
{
if(Utility(n, m, x + 1, y))
{
return true;
}
}
if(Safe(n, m, x, y + 1))
{
if(Utility(n, m, x, y + 1)) // checking if it is viable to move right
{
return true;
}
}
if(Safe(n, m, x - 1, y))
{
if(Utility(n, m, x - 1, y)) // checking if it is viable to move up
{
return true;
}
}
if(Safe(n, m, x, y - 1))
{
if(Utility(n, m, x, y - 1)) // checking if it is viable to move left
{
return true;
}
}
}
return false; // returning false
}
int main()
{
int n, m;
cin >> n >> m; // input dimensions of the maze
for(int i = 0; i < n; i++) // input maze
{
for(int j = 0; j < m; j++)
{
char c;
cin >> c;
if(c == '.') //character '.' means a tile which you can go through
{
maze[i][j] = true;
}
else //character 'x' means a tile which you cannot go through
{
maze[i][j] = false;
}
///////////// change here /////////////
visited[i][j] = false;
}
}
if(Utility(n, m, 0, 0)) //printing yes or no
{
cout << "da";
}
else
{
cout << "ne";
}
return 0;
}
Here's the link where I tested it: https://ideone.com/vVqAjF

Group Consecutive Neighbouring Black Pixels Together with OpenCV [duplicate]

I am looking for an OpenCV function that can find connected components and perform a few tasks on them ( like getting the number of pixels, contour, list of pixels in the object etc.. )
Is there a function of OpenCV (C++) that is similar to MatLab's regionprops ?
Starting from version 3.0, OpenCV has connectedComponents function.
Have a look at the cvFindContours function. It's very versatile -- it can find both interior and exterior contours, and return the results in a variety of formats (e.g. flat list vs. tree structure). Once you have the contours, functions like cvContourArea allow you to determine basic properties of the connected component corresponding to a particular contour.
If you prefer to use the newer C++ interface (as opposed to the older C-style interface I described above), then the function names are similar.
set -std=c++0x option when compiling
.h file
//connected_components.h
#ifndef CONNECTED_COMPONENTS_H_
#define CONNECTED_COMPONENTS_H_
#include <opencv2/core/core.hpp>
#include <memory>
class DisjointSet {
private:
std::vector<int> m_disjoint_array;
int m_subset_num;
public:
DisjointSet();
DisjointSet(int size);
~DisjointSet();
int add(); //add a new element, which is a subset by itself;
int find(int x); //return the root of x
void unite(int x, int y);
int getSubsetNum(void);
};
class ConnectedComponent {
private:
cv::Rect m_bb;
int m_pixel_count;
std::shared_ptr< std::vector<cv::Point2i> > m_pixels;
public:
ConnectedComponent();
ConnectedComponent(int x, int y);
~ConnectedComponent();
void addPixel(int x, int y);
int getBoundingBoxArea(void) const;
cv::Rect getBoundingBox(void) const;
int getPixelCount(void) const;
std::shared_ptr< const std::vector<cv::Point2i> > getPixels(void) const;
};
void findCC(const cv::Mat& src, std::vector<ConnectedComponent>& cc);
#endif //CONNECTED_COMPONENTS_H_
.cc file
//connected_components.cpp
#include "connected_components.h"
using namespace std;
/** DisjointSet **/
DisjointSet::DisjointSet() :
m_disjoint_array(),
m_subset_num(0)
{ }
DisjointSet::DisjointSet(int size) :
m_disjoint_array(),
m_subset_num(0)
{
m_disjoint_array.reserve(size);
}
DisjointSet::~DisjointSet()
{ }
//add a new element, which is a subset by itself;
int DisjointSet::add()
{
int cur_size = m_disjoint_array.size();
m_disjoint_array.push_back(cur_size);
m_subset_num ++;
return cur_size;
}
//return the root of x
int DisjointSet::find(int x)
{
if (m_disjoint_array[x] < 0 || m_disjoint_array[x] == x)
return x;
else {
m_disjoint_array[x] = this->find(m_disjoint_array[x]);
return m_disjoint_array[x];
}
}
// point the x and y to smaller root of the two
void DisjointSet::unite(int x, int y)
{
if (x==y) {
return;
}
int xRoot = find(x);
int yRoot = find(y);
if (xRoot == yRoot)
return;
else if (xRoot < yRoot) {
m_disjoint_array[yRoot] = xRoot;
}
else {
m_disjoint_array[xRoot] = yRoot;
}
m_subset_num--;
}
int DisjointSet::getSubsetNum()
{
return m_subset_num;
}
/** ConnectedComponent **/
ConnectedComponent::ConnectedComponent() :
m_bb(0,0,0,0),
m_pixel_count(0),
m_pixels()
{
m_pixels = std::make_shared< std::vector<cv::Point2i> > ();
}
ConnectedComponent::ConnectedComponent(int x, int y) :
m_bb(x,y,1,1),
m_pixel_count(1),
m_pixels()
{
m_pixels = std::make_shared< std::vector<cv::Point2i> > ();
}
ConnectedComponent::~ConnectedComponent(void)
{ }
void ConnectedComponent::addPixel(int x, int y) {
m_pixel_count++;
// new bounding box;
if (m_pixel_count == 0) {
m_bb = cv::Rect(x,y,1,1);
}
// extend bounding box if necessary
else {
if (x < m_bb.x ) {
m_bb.width+=(m_bb.x-x);
m_bb.x = x;
}
else if ( x > (m_bb.x+m_bb.width) ) {
m_bb.width=(x-m_bb.x);
}
if (y < m_bb.y ) {
m_bb.height+=(m_bb.y-y);
m_bb.y = y;
}
else if ( y > (m_bb.y+m_bb.height) ) {
m_bb.height=(y-m_bb.y);
}
}
m_pixels->push_back(cv::Point(x,y));
}
int ConnectedComponent::getBoundingBoxArea(void) const {
return (m_bb.width*m_bb.height);
}
cv::Rect ConnectedComponent::getBoundingBox(void) const {
return m_bb;
}
std::shared_ptr< const std::vector<cv::Point2i> > ConnectedComponent::getPixels(void) const {
return m_pixels;
}
int ConnectedComponent::getPixelCount(void) const {
return m_pixel_count;
}
/** find connected components **/
void findCC(const cv::Mat& src, std::vector<ConnectedComponent>& cc) {
if (src.empty()) return;
CV_Assert(src.type() == CV_8U);
cc.clear();
int total_pix = src.total();
int frame_label[total_pix];
DisjointSet labels(total_pix);
int root_map[total_pix];
int x, y;
const uchar* cur_p;
const uchar* prev_p = src.ptr<uchar>(0);
int left_val, up_val;
int cur_idx, left_idx, up_idx;
cur_idx = 0;
//first logic loop
for (y = 0; y < src.rows; y++ ) {
cur_p = src.ptr<uchar>(y);
for (x = 0; x < src.cols; x++, cur_idx++) {
left_idx = cur_idx - 1;
up_idx = cur_idx - src.size().width;
if ( x == 0)
left_val = 0;
else
left_val = cur_p[x-1];
if (y == 0)
up_val = 0;
else
up_val = prev_p[x];
if (cur_p[x] > 0) {
//current pixel is foreground and has no connected neighbors
if (left_val == 0 && up_val == 0) {
frame_label[cur_idx] = (int)labels.add();
root_map[frame_label[cur_idx]] = -1;
}
//current pixel is foreground and has left neighbor connected
else if (left_val != 0 && up_val == 0) {
frame_label[cur_idx] = frame_label[left_idx];
}
//current pixel is foreground and has up neighbor connect
else if (up_val != 0 && left_val == 0) {
frame_label[cur_idx] = frame_label[up_idx];
}
//current pixel is foreground and is connected to left and up neighbors
else {
frame_label[cur_idx] = (frame_label[left_idx] > frame_label[up_idx]) ? frame_label[up_idx] : frame_label[left_idx];
labels.unite(frame_label[left_idx], frame_label[up_idx]);
}
}//endif
else {
frame_label[cur_idx] = -1;
}
} //end for x
prev_p = cur_p;
}//end for y
//second loop logic
cur_idx = 0;
int curLabel;
int connCompIdx = 0;
for (y = 0; y < src.size().height; y++ ) {
for (x = 0; x < src.size().width; x++, cur_idx++) {
curLabel = frame_label[cur_idx];
if (curLabel != -1) {
curLabel = labels.find(curLabel);
if( root_map[curLabel] != -1 ) {
cc[root_map[curLabel]].addPixel(x, y);
}
else {
cc.push_back(ConnectedComponent(x,y));
root_map[curLabel] = connCompIdx;
connCompIdx++;
}
}
}//end for x
}//end for y
}
If you don't mind using an external library that uses OpenCV, you can do that using cvBlobsLib.
A library to perform binary images connected component labelling
(similar to regionprops Matlab function). It also provides functions
to manipulate, filter and extract results from the extracted blobs,
see features section for more information.
You can use cv::connectedComponentsWithStats() function.
Here is an example.
// ...
cv::Mat labels, stats, centroids;
int connectivity = 8; // or 4
int label_count = cv::connectedComponentsWithStats(src, labels, stats, centroids, connectivity);
for (int i = 0; i < label_count; i++)
{
int x = stats.at<int>(i, cv::CC_STAT_LEFT);
int y = stats.at<int>(i, cv::CC_STAT_TOP);
int w = stats.at<int>(i, cv::CC_STAT_WIDTH);
int h = stats.at<int>(i, cv::CC_STAT_HEIGHT);
int area = stats.at<int>(i, cv::CC_STAT_AREA);
double cx = centroids.at<double>(i, 0);
double cy = centroids.at<double>(i, 1);
// ...
}
Following DXM's code above which assumes 4-connected components, here is a version for 'findCC' that detects 8-connected components.
void findCC(const cv::Mat& src, std::vector<ConnectedComponent>& cc) {
if (src.empty()) return;
CV_Assert(src.type() == CV_8U);
cc.clear();
int total_pix = int(src.total());
int *frame_label = new int[total_pix];
DisjointSet labels(total_pix);
int *root_map = new int[total_pix];
int x, y;
const uchar* cur_p;
const uchar* prev_p = src.ptr<uchar>(0);
int left_val, up_val, up_left_val, up_right_val;
int cur_idx, left_idx, up_idx, up_left_idx, up_right_idx;
cur_idx = 0;
//first logic loop
for (y = 0; y < src.rows; y++) {
cur_p = src.ptr<uchar>(y);
for (x = 0; x < src.cols; x++, cur_idx++) {
left_idx = cur_idx - 1;
up_idx = cur_idx - src.size().width;
up_left_idx = up_idx - 1;
up_right_idx = up_idx + 1;
if (x == 0)
{
left_val = 0;
}
else
{
left_val = cur_p[x - 1];
}
if (y == 0)
{
up_val = 0;
}
else
{
up_val = prev_p[x];
}
if (x == 0 || y == 0)
{
up_left_val = 0;
}
else
{
up_left_val = prev_p[x-1];
}
if (x == src.cols - 1 || y == 0)
{
up_right_val = 0;
}
else
{
up_right_val = prev_p[x+1];
}
if (cur_p[x] > 0) {
//current pixel is foreground and has no connected neighbors
if (left_val == 0 && up_val == 0 && up_left_val == 0 && up_right_val == 0) {
frame_label[cur_idx] = (int)labels.add();
root_map[frame_label[cur_idx]] = -1;
}
//Current pixel is foreground and has at least one neighbor
else
{
vector<int> frame_lbl;
frame_lbl.reserve(4);
//Find minimal label
int min_frame_lbl = INT_MAX;
int valid_entries_num = 0;
if (left_val != 0)
{
frame_lbl.push_back(frame_label[left_idx]);
min_frame_lbl = min(min_frame_lbl, frame_label[left_idx]);
valid_entries_num++;
}
if (up_val != 0)
{
frame_lbl.push_back(frame_label[up_idx]);
min_frame_lbl = min(min_frame_lbl, frame_label[up_idx]);
valid_entries_num++;
}
if (up_left_val != 0)
{
frame_lbl.push_back(frame_label[up_left_idx]);
min_frame_lbl = min(min_frame_lbl, frame_label[up_left_idx]);
valid_entries_num++;
}
if (up_right_val != 0)
{
frame_lbl.push_back(frame_label[up_right_idx]);
min_frame_lbl = min(min_frame_lbl, frame_label[up_right_idx]);
valid_entries_num++;
}
CV_Assert(valid_entries_num > 0);
frame_label[cur_idx] = min_frame_lbl;
//Unite if necessary
if (valid_entries_num > 1)
{
for (size_t i = 0; i < frame_lbl.size(); i++)
{
labels.unite(frame_lbl[i], min_frame_lbl);
}
}
}
}//endif
else {
frame_label[cur_idx] = -1;
}
} //end for x
prev_p = cur_p;
}//end for y
//second loop logic
cur_idx = 0;
int curLabel;
int connCompIdx = 0;
for (y = 0; y < src.size().height; y++) {
for (x = 0; x < src.size().width; x++, cur_idx++) {
curLabel = frame_label[cur_idx];
if (curLabel != -1) {
curLabel = labels.find(curLabel);
if (root_map[curLabel] != -1) {
cc[root_map[curLabel]].addPixel(x, y);
}
else {
cc.push_back(ConnectedComponent(x, y));
root_map[curLabel] = connCompIdx;
connCompIdx++;
}
}
}//end for x
}//end for y
//Free up allocated memory
delete[] frame_label;
delete[] root_map;
}

Having trouble inserting into heap

Below is my C++ code for inserting into a heap. The value for k is inserted but it's inserted at the bottom. I expected it to heapify with that while loop.
void Insert(heap1* myHeap, int k)
{
(myHeap->size)++;
int i = myHeap->size;
while (i > 1 && myHeap->H[i/2].key < k)
{
myHeap->H[i].key = myHeap->H[i/2].key;
i = i/2;
}
myHeap->H[i].key = k;
}
I do have a heapify procedure that I tried to use for this before this attempt that I know works within my other heap procedures. I just can't get it to work within Insert so I went with the above route. Below is heapify just in case its useful:
void heapify(heap1* myHeap, int i)
{
int l = 2 * i;
int r = 2 * i + 1;
int largest;
if (l <= myHeap->size && myHeap->H[l].key > myHeap->H[i].key)
largest = l;
else
largest = i;
if (r <= myHeap->size && myHeap->H[r].key > myHeap->H[largest].key)
largest = r;
if (largest != i)
{
myHeap->H[i].key = myHeap->H[i].key + myHeap->H[largest].key;
myHeap->H[largest].key = myHeap->H[i].key - myHeap->H[largest].key;
myHeap->H[i].key = myHeap->H[i].key - myHeap->H[largest].key;
heapify(myHeap, largest);
}
}
If someone could lead me in the right direction on how to get it to restore its heap properties, I would largely appreciate it.
try using this code:
void insert(int heap[], int *n, int item){
(*n)++;
heap[*n] = item;
reheapify_upward(heap, *n);
}
void reheapify_upward(int heap[],int start){
int temp,parent;
if(start>1){
parent=start/2;
if(heap[parent]<heap[start]){
temp=heap[start];
heap[start]=heap[parent];
heap[parent]=temp;
reheapify_upward(heap,parent);
}
}
}

algorithm for finding primitive pythagorean triples

here is my code:
// PPT.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
#include <stdio.h>
#include <stdlib.h>
#define LOWER_BOUND 1
#define UPPER_BOUND 20
struct ppt
{
int v1;
int v2;
int v3;
ppt *next;
};
typedef struct ppt PPT;
typedef PPT *ppt_ptr;
void insert_ppt(ppt_ptr *h_ptr, ppt_ptr *t_ptr, int u1, int u2, int u3);
void print_ppt(ppt_ptr curr_ptr);
int is_prime(int n);
int is_pythagorean_triplet(int v1, int v2, int v3);
int different_triples(int v1, int v2, int v3, int u1, int u2, int u3);
int are_exact_multiples(int p, int q, int r, int l, int m, int n);
int is_unique_and_insertable(ppt_ptr curr_ptr, int v1, int v2, int v3);
//====================================================================
int _tmain(int argc, _TCHAR* argv[])
{
ppt_ptr head_ptr = NULL;
ppt_ptr tail_ptr = NULL;
for (int a = LOWER_BOUND; a <= UPPER_BOUND; a++)
{
for (int b = LOWER_BOUND; b <= UPPER_BOUND; b++)
{
for (int c = LOWER_BOUND; c <= UPPER_BOUND; c++)
{
if(is_pythagorean_triplet(a,b,c) == 1)
{
if(head_ptr == NULL)
{
//printf("%d %d %d",a,b,c);
insert_ppt(&head_ptr,&tail_ptr,a,b,c);
}
//printf("%d %d %d",a,b,c);
if(is_unique_and_insertable(tail_ptr,a,b,c) == 1)
{
//printf("%d %d %d\n",a,b,c);
insert_ppt(&head_ptr,&tail_ptr,a,b,c);
}
}
}
}
}
//print_ppt(head_ptr);
getchar();
getchar();
return 0;
}
this function inserts a new node at end of list
void insert_ppt(ppt_ptr *h_ptr, ppt_ptr *t_ptr, int u1, int u2, int u3)
{
ppt_ptr new_ptr;
new_ptr = ppt_ptr( malloc( sizeof(PPT) ) );
if(new_ptr != NULL)
{
new_ptr->v1 = u1;
new_ptr->v2 = u2;
new_ptr->v3 = u3;
new_ptr->next = NULL;
if(*h_ptr == NULL)
{
*h_ptr = new_ptr;
}
else
{
(*t_ptr)->next = new_ptr;
}
*t_ptr = new_ptr;
}
else
{
printf("%d %d %d not inserted. No memory available.\n",u1,u2,u3);
}
}
this function prints list
void print_ppt(ppt_ptr curr_ptr)
{
if(curr_ptr == NULL)
{
printf("List is empty.\n\n");
}
else
{
while(curr_ptr != NULL)
{
printf("%d %d %d\n",curr_ptr->v1,curr_ptr->v2,curr_ptr->v3);
curr_ptr = curr_ptr->next;
}
}
}
this function determines if a number is prime
// Function 1
int is_prime(int n)
{
int num_of_factors = 0;
int i = 1;
for (i=1; i<=n; i++)
{
if (n % i == 0)
{
num_of_factors ++;
}
}
if (num_of_factors == 2)
{
return 1;
}
else
{
return 0;
}
}
this function determines if a triplet is pythagorean
// Function 2
int is_pythagorean_triplet(int v1, int v2, int v3)
{
if ( (v1*v1 + v2*v2 == v3*v3) || (v2*v2 + v3*v3 == v1*v1) || (v1*v1 + v3*v3 == v2*v2) )
{
return 1;
}
else
{
return 0;
}
}
this function determines if a triplet is unique and this is the function that i am having trouble with
int is_unique_and_insertable(ppt_ptr curr_ptr, int v1, int v2, int v3)
{
if(curr_ptr == NULL)
{
//printf("List is empty.\n\n");
}
else
{
if(curr_ptr != NULL)
{
//printf("%d %d %d\n",curr_ptr->v1,curr_ptr->v2,curr_ptr->v3);
int u1 = curr_ptr->v1;
int u2 = curr_ptr->v2;
int u3 = curr_ptr->v3;
if( (different_triples(v1,v2,v3,u1,u2,u3)) &&
(!are_exact_multiples(v1,v2,v3,u1,u2,u3) ) )
{
printf("%d %d %d\n",curr_ptr->v1,curr_ptr->v2,curr_ptr->v3);
return 1;
}
//printf("yoyoyo");
curr_ptr = curr_ptr->next;
}
}
return 0;
}
this function determines if a triple is unique
// Definition: This function checks if <v1,v2,v3> and <u1,u2,u3> are different triplets
// or not. If they are different triplets, it returns 1.
int different_triples(int v1, int v2, int v3, int u1, int u2, int u3)
{
if (v1==u1 && v2==u2 && v3==u3)
return 0;
else if (v1==u1 && v2==u3 && v3==u2)
return 0;
else if (v1==u2 && v2==u1 && v3==u3)
return 0;
else if (v1==u2 && v2==u3 && v3==u1)
return
else if (v1==u3 && v2==u2 && v3==u1)
return 0;
else if (v1==u3 && v2==u1 && v3==u2)
return 0;
else
return 1;
}
this function determines if a triplet is a multiple of a triplet
// This function tests if the triplet <p,q,r> is an exact multiple of <l,m,n> in any order
// (arrangement/permutation)
int are_exact_multiples(int v1, int v2, int v3, int u1, int u2, int u3)
{
if (v1%u1==0 && v2%u2==0 && v3%u3==0)
return 1;
else if (u1%v1==0 && u2%v2==0 && u3%v3==0)
return 1;
else if (v1%u1==0 && v2%u3==0 && v3%u2==0)
return 1;
else if (u1%v1==0 && u2%v3==0 && u3%v2==0)
return 1;
else if (v1%u2==0 && v2%u1==0 && v3%u3==0)
return 1;
else if (v1%u2==0 && v2%u3==0 && v3%u1==0)
return 1;
else if (u1%v2==0 && u2%v1==0 && u3%v3==0)
return 1;
else if (u1%v2==0 && u2%v3==0 && u3%v1==0)
return 1;
else if (v1%u3==0 && v2%u2==0 && v3%u1==0)
return 1;
else if (v1%u3==0 && v2%u1==0 && v3%u2==0)
return 1;
else if (u1%v3==0 && u2%v2==0 && u3%v1==0)
return 1;
else if (u1%v3==0 && u2%v1==0 && u3%v2==0)
return 1;
else
return 0;
}
I know that the algorithm is not optimized... i will do that later. Can somebody please help me get this code to work.
Your function is_unique_and_insertable presumably should check whether an equivalent triple (the same numbers in different order) is already present in the list or the new triple is a multiple (modulo permutations) of a triple in the list. But it only compares the new triple to the first list element, there is no looping statement or recursion in the function.
int is_unique_and_insertable(ppt_ptr curr_ptr, int v1, int v2, int v3)
{
if(curr_ptr == NULL)
{
//printf("List is empty.\n\n");
}
else
{
if(curr_ptr != NULL)
{
//printf("%d %d %d\n",curr_ptr->v1,curr_ptr->v2,curr_ptr->v3);
int u1 = curr_ptr->v1;
int u2 = curr_ptr->v2;
int u3 = curr_ptr->v3;
if( (different_triples(v1,v2,v3,u1,u2,u3)) &&
(!are_exact_multiples(v1,v2,v3,u1,u2,u3) ) )
{
printf("%d %d %d\n",curr_ptr->v1,curr_ptr->v2,curr_ptr->v3);
return 1;
}
//printf("yoyoyo");
curr_ptr = curr_ptr->next;
}
}
return 0;
}
You would get it to compare to more than just the first element if you used a while(curr_ptr != NULL). However, it would still have the wrong logic, it would return true (1) as soon as it finds a different triple the new one is not a multiple of.
The logic must be the other way round, if an equivalent triple (or a triple the new one is a multiple of) is encountered, then you return false (0), only if the entire list is traversed without encountering such a triple should you return true:
int is_unique_and_insertable(ppt_ptr curr_ptr, int v1, int v2, int v3)
{
while(curr_ptr != NULL)
{
int u1 = curr_ptr->v1;
int u2 = curr_ptr->v2;
int u3 = curr_ptr->v3;
if (!different_triples(v1, v2, v3, u1, u2, u3) || are_exact_multiples(v1, v2, v3, u1, u2, u3))
{
return 0;
}
curr_ptr = curr_ptr->next;
}
return 1;
}
That takes you closer to a correct program, but your are_exact_multiples function is faulty, it would declare (15, 36, 39) to be a multiple of (3, 4, 5), although it isn't.
You would get a much simpler and easier to get right program if you only considered triples (a, b, c) with a <= b <= c (actually, a < b < c, since a Pythagorean triple can't have two equal components).
You said you would treat efficiency later, but please do that soon, your is_prime function is painfully inefficient. You should stop as soon as you found the first nontrivial divisor, and you can stop when you've reached the square root:
int is_prime(int n)
{
if (n < 2) return 0;
if (n%2 == 0) return n == 2;
for(int d = 3; d*d <= n; d += 2)
{
if (n%d == 0) return 0;
}
return 1;
}