select desired paths through binary tree - c++

I have already asked a question here. And I achieved the answer.
Actually, this is a kind of different path, i.e., I have two options for each level, up(1) or down(-1), and I have the n level. Therefore I have 2^n path.
Now in this current question, I want to select some desired paths.
My desired paths have two conditions as follows.
The end of a given path reaches, let say, 1.
Thus, I want to select those paths which finally reach 1i.e., the sum of a given path with n level is 1.
I want to bound those paths in #1 between, let say, 9 and -9. For example, I want to avoid the sum of 9 up or 9 down in sequence, which is bigger than 9 and less than -9.
Here is my attempt:
int popcount(unsigned x){
int c = 0;
for (; x != 0; x >>= 1)
if (x & 1)
c++;
return c;
}
void selected_path(vector<int> &d, int n){
d.clear();
int size = 1<<n;
d.resize(size);
for (int i = 0; i < size; ++i) {
d[i] = n-2.0*popcount(i);
}
}
In the above code, d[] gives me all possible paths, i.e. 2^n. But I want to select those paths with the above 2 conditions.
Edit: the answer but not efficient!
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
struct node{
int data;
node *left, *right;
};
struct node *create(int x, int n, int limit){
struct node *newnode;
newnode = new node();
n++;
if(n==(limit+2)) return 0;
newnode->data = x;
x = newnode->data + 1;
newnode->left = create(x,n,limit);
x = newnode->data -1 ;
newnode->right = create(x, n,limit);
return newnode;
}
void inorder(std::vector<int> &d, node *root, vector<int> &stack, int uplimit, int downlimit){ //uplimit,downlimit
if(root == NULL) return;
stack.push_back(root->data);
inorder(d,root->left,stack,uplimit,downlimit);
if(root->left == 0 and root->right ==0){
if(stack[stack.size() -1] == 1){
int max=*max_element(stack.begin(), stack.end());
int min=*min_element(stack.begin(), stack.end());
if(max < uplimit and min > downlimit){
for(int i = 1; i < stack.size(); i++){
d.push_back(stack[i]);
}
}
}
}
inorder(d,root->right,stack,uplimit,downlimit);
stack.pop_back();
}
int main(){
int limit = 7;
struct node *root;
root = create(0,0,limit);
std::vector<int> stack;
std::vector<int> d;
int uplimit = 9;
int downlimit = -9;
inorder(d,root, stack,uplimit,downlimit);
stack.clear();
int n_path = int(d.size()/(limit));
for(int ip =0; ip < n_path; ip++){
for(int i = 1; i <=limit; i++){
cout << d[ip*(limit)+(i-1)] << "\t";
}
cout << endl;
}
}
A possible answer can be as above code. Here d[] is a two-dimension array, which is the first one is the number of the paths, and the second dimension is the value of nodes during the path.
But the problem is that it is not efficient in terms of memory (if limit > 20) due to the root-> data saves all possible nodes, which is unnecessary.
I would highly appreciate it if one could give some idea to make it efficient

Related

Different results during Debug and Run in C++

I'm working on a algorithm problem, and it discribed as follows:
Suppose the deep learning model is a directed acyclic graph. If operator A depends on the output of operator B, then A can be calculated after the execution of B. If there is no dependency relation, then A can be executed in parallel. Given N nodes, the information of each node contains the execution time of the node and the list of the next nodes, and the shortest execution time of the neural network is calculated. The node index starts at 0.
and here is the input example:
7
A 10 1 2 3
B 9 4 5 6
C 22
D 20
E 19
F 18
G 21
Here is my solution:
#include <bits/stdc++.h>
using namespace std;
int dfs(int nodeTime, const vector<int>& nextNodes, vector<vector<int>> NN){
// Check whether the children of the current node have children
bool is_end = true;
for (int node : nextNodes) {
if (NN[node][1] != 0){
is_end = false;
break;
}
}
//The children of the current node have no children, find the maxTime
if (is_end) {
int maxTime = 0;
for (int node : nextNodes) {
maxTime = max(node, maxTime);
}
return nodeTime + maxTime;
}
//some children of the current node have children, keep doing dfs()
else{
int maxTime = 0;
for (int nodeIdx : nextNodes) {
if (NN[nodeIdx].size() != 1){
vector<int> next;
next.assign(NN[nodeIdx].begin() + 1, NN[nodeIdx].end());
maxTime = max(maxTime, dfs(NN[nodeIdx][0], next, NN));
}
else maxTime = max(maxTime, NN[nodeIdx][0]);
}
return maxTime + nodeTime;
}
}
int str_int(const string& s){
char c[10];
strcpy(c, s.c_str());
return atoi(c);
}
int main() {
// input stage
int n;
cin >> n;
vector<vector<int>> NN;
vector<int> temp;
vector<string> stemp;
string s;
for (int i = 0; i < n; ++i) {
stemp.clear();
temp.clear();
while (cin >> s){
stemp.push_back(s);
if (getchar() == '\n') break;
}
for (int j = 1; j < stemp.size(); ++j) {
temp.push_back(str_int(stemp[j]));
}
NN.push_back(temp);
}
vector<int> initialNextNodes; //Initialize the sequence of children of the starting node
initialNextNodes.assign(NN[0].begin() + 1, NN[0].end());
int res = dfs(NN[0][0], initialNextNodes, NN);
cout << res;
return 0;
}
The right output is 40, Debug mode gives the right answer, but Run mode gives the wrong answer, I can't figure out what went wrong. I looked up the common causes of this error, probably a pointer being used without space allocated, or a variable being used without an initial value assigned. But these do not seem to be the answer to my question, can anyone help me? I would be so grateful.

Find the Largest Distance between nodes of a Tree ? Can someone explain me the approach for this

Link to problem
InterviewBit solution to the problem
int Solution::solve(vector<int> &A)
{
vector<int> hgt(A.size(),0);
int ans=0,maxx=0;
for(int i=A.size()-1;i>0;i--)
{
ans=max(ans,hgt[A[i]]+hgt[i]+1);
hgt[A[i]]=max(hgt[i]+1,hgt[A[i]]);
}
return ans;
}
Can someone explain to me the above code as well as their approach where they said as follows :
Pick any node u.
Find the node which is farthest from u, call it x.
Find the node which is farthest from x, call it q.
The answer will be the length of a path from x to q.
Basically the problem is to find out the diameter of a tree.
Diameter of a Tree - It is the longest path between two nodes in a
tree.
Longest path will always occur between two leaf nodes.
Let's say, from given array you have made the tree.
Now you can use 2 DFS or BFS to do it.
Procedure:
Start BFS from a random node (let's say we run from root node) and
find out the farthest node from it. Let the farthest node be X. It is
clear that X will always be a leaf node.
Now if we start BFS from X and check the farthest node from it (like
we did previously), we will get the diameter of the tree.
Sample code:
#define MAX 40001
vector<int> adj[MAX];
int dist[MAX];
int totalNode;
pair<int, int> _bfs(int startingNode) {
for(int i=0; i <= totalNode; i++) {
dist[i] = 0;
}
dist[startingNode] = 1;
int maxDistance = 0, farthestNode;
queue<int> q;
q.push(startingNode);
while(!q.empty()) {
int currNode = q.front();
q.pop();
int sz = adj[currNode].size();
for(int i = 0; i < sz; i++) {
int nextNode = adj[currNode][i];
if(dist[nextNode] == 0) {
dist[nextNode] = dist[currNode] + 1;
q.push(nextNode);
if(dist[nextNode] > maxDistance) {
maxDistance = dist[nextNode], farthestNode = nextNode;
}
}
}
}
return {farthestNode, maxDistance};
}
int _getDiameter(int &rootNode) {
// Running the first BFS from the root node (as explained in the procedue 1)
pair<int, int> pii = _bfs(rootNode);
// Running the second BFS from the furthest node we've found after running first BFS (as explained in the procedure 2)
pair<int, int> pii2 = _bfs(pii.first);
return pii2.second;
}
int Solution::solve(vector<int> &A) {
totalNode = A.size();
int rootNode;
if(totalNode == 1) return 0;
if(totalNode == 2) return 1;
for(int i = 0; i < totalNode; i++) adj[i].clear();
for(int i = 0; i < totalNode; i++) {
int n = A[i];
if(n == -1) rootNode = i;
else adj[i].push_back(n), adj[n].push_back(i);
}
return _getDiameter(rootNode) - 1;
}
Reference:
Diameter of a tree using DFS
Finding Diameter of a Tree using DFS with proof

Is the Union-Find (or Disjoint Set) data structure in STL?

I would have expected such a useful data structure to be included in the C++ Standard Library but I can't seem to find it.
It is not, but there is one in boost: http://www.boost.org/doc/libs/1_64_0/libs/disjoint_sets/disjoint_sets.html, so if you want an off-the-shelf implementation I'd recommend this.
No. I written a simple implementation. It's very extensible.
struct DisjointSet {
vector<int> parent;
vector<int> size;
DisjointSet(int maxSize) {
parent.resize(maxSize);
size.resize(maxSize);
for (int i = 0; i < maxSize; i++) {
parent[i] = i;
size[i] = 1;
}
}
int find_set(int v) {
if (v == parent[v])
return v;
return parent[v] = find_set(parent[v]);
}
void union_set(int a, int b) {
a = find_set(a);
b = find_set(b);
if (a != b) {
if (size[a] < size[b])
swap(a, b);
parent[b] = a;
size[a] += size[b];
}
}
};
And the usage as follows.
void solve() {
int n;
cin >> n;
DisjointSet S(n); // Initializing with maximum Size
S.union_set(1, 2);
S.union_set(3, 7);
int parent = S.find_set(1); // root of 1
}
The implementation of disjoint set using tree. There are two operations:
find_set(x): get representative of set which contains member x, here representative is the root node
union_set(x,y): union of two sets which contain members x and y
Tree representation is efficient than linked list representation with two heuristics:
-- "union by rank" and "path compression" --
union by rank: assign rank to each node. Rank is height of the node (number of edges in the longest simple path between the node and a descendant leaf)
path compression: during "find_set" operation, make parent of node as root
(Ref: Introduction to Algorithms, 3rd Edition by CLRS)
The STL implementation is given below:
#include <iostream>
#include <vector>
using namespace std;
struct disjointSet{
vector<int> parent, rank;
disjointSet(int n){
rank.assign(n, 0);
for (int i = 0; i < n; i++)
parent.push_back(i);
}
int find_set(int v){
if(parent[v]!=v)
parent[v] = find_set(parent[v]);
return parent[v];
}
void union_set(int x,int y){
x = find_set(x);
y = find_set(y);
if (rank[x] > rank[y])
parent[y] = x;
else{
parent[x] = y;
if(rank[x]==rank[y])
rank[y]++;
}
}
};

Path finding using dfs and bfs

my undirected graph is this:-
{0,1,1,0,0,
1,0,0,1,0,
1,0,0,1,0,
0,1,1,0,1,
0,0,0,1,0};
i want to find the path between two nodes using bfs and dfs as my assignment.
when i perform bfs i simply print the nodes which should be minimum path but it shows 01234 but i want is 0134 or 0234 and when i perform dfs it gives 01324.
my bfs code:-
#include <iostream>
#include<queue>
using namespace std;
int main(){
int matrix[5][5]={0,1,1,0,0,
1,0,0,1,0,
1,0,0,1,0,
0,1,1,0,1,
0,0,0,1,0};
//int nodes[3] = {5,6,7};
int visited[5] = {0,0,0,0,0};
int inNode,pathNode;
cout<<"Enter Initial Node: ";
cin>>inNode;
cout<<"Enter Path Node: ";
cin>>pathNode;
int traceBack[5],rec=0;
queue<int> myqueue;
myqueue.push(inNode);
int node = myqueue.front();
visited[inNode] = 1;
//cout<<node<<"\n";
while(!myqueue.empty()){
int s = myqueue.front();
myqueue.pop();
for(int i =0 ; i<5;i++){
if(matrix[s][i] == 1 && visited[i] == 0){
myqueue.push(i);
visited[i] = 1;
traceBack[rec] = i;
rec++;
}
}
}
cout<<inNode;
int j = 0;
while(traceBack[j]!=pathNode){
cout<<"->"<<traceBack[j];
j++;
}
cout<<"->"<<pathNode;
return 0;
}
my dfs code:-
#include<iostream>
using namespace std;
int visited[5]= {0,0,0,0,0};
int traceBack[5],rec=0;
int matrix[5][5]={0,1,1,0,0,
1,0,0,1,0,
1,0,0,1,0,
0,1,1,0,1,
0,0,0,1,0};
void dfs(int v){
int i;
visited[v]=1;
for(i= 0 ; i<5;i++){
if(matrix[v][i] && visited[i]==0){
traceBack[rec] = i;
rec++;
cout<<i;
dfs(i);
}
}
}
int main(){
int inNode,pathNode;
cout<<"Enter Initial Node: ";
cin>>inNode;
cout<<"Enter Path Node: ";
cin>>pathNode;
dfs(inNode);
int k=0;
while(traceBack[k]!=pathNode)
{
k++;
cout<<traceBack[k];
}
return 0;
}
The problem is that the "traceBack" is not actually tracing back. It just contains the order in which nodes were visited, which is not necessarily the path that you want.
What you need to do?
When some node s accesses another node i, then traceBack[i] = s. Why? because it says that i was accessed from s, this way every node can follow its trace back. (you also initialize traceBack[inNode] = -1 since this node was not accessed by anybody)
Now, when the algorithm is finished the following code will give you the path. (It first gets the path in reverse order and then reverses it to get the correct order)
int i = pathNode;
int path[1000];
int path_len = 0;
//this gives you the path in reverse order
while(traceBack[i] != -1){ // there is something to trace
path[path_len++] = i;
i = traceBack[i];
}
path[path_len++] = inNode; // the inNode is left out in the while loop
//printing the path in right order
for(int j = path_len - 1; j >= 0; j—-){
cout << path[j] << " -> ";
}
You problem is, for BFS, you cannot use the same method to trace back as you use for DFS. You may modify your code as follow:
while(!myqueue.empty()){
int s = myqueue.front();
myqueue.pop();
for(int i =0 ; i<5;i++){
if(matrix[s][i] == 1 && visited[i] == 0){
myqueue.push(i);
visited[i] = 1;
traceBack[i] = s;
}
}
}
So, now, traceBack contains the parent of each node. To find path from node 4 to 0:
int j = pathNode;
while(traceBack[j]!=0){
cout<<"<-"<<traceBack[j];
j++;
}
cout<<"<-"<<0;

Trouble with Dijkstra , finding all minimum paths

We have a problem here, we're trying to find all the shortest paths in graph from one node to another. We have already implemented dijkstra but we really dont know how to find them all.
Do we have to use BFS?
#include <vector>
#include <iostream>
#include <queue>
using namespace std;
typedef pair <int, int> dist_node;
typedef pair <int, int> edge;
const int MAXN = 10000;
const int INF = 1 << 30;
vector <edge> g[MAXN];
int d[MAXN];
int p[MAXN];
int dijkstra(int s, int n,int t){
for (int i = 0; i <= n; ++i){
d[i] = INF; p[i] = -1;
}
priority_queue < dist_node, vector <dist_node>,greater<dist_node> > q;
d[s] = 0;
q.push(dist_node(0, s));
while (!q.empty()){
int dist = q.top().first;
int cur = q.top().second;
q.pop();
if (dist > d[cur]) continue;
for (int i = 0; i < g[cur].size(); ++i){
int next = g[cur][i].first;
int w_extra = g[cur][i].second;
if (d[cur] + w_extra < d[next]){
d[next] = d[cur] + w_extra;
p[next] = cur;
q.push(dist_node(d[next], next));
}
}
}
return d[t];
}
vector <int> findpath (int t){
vector <int> path;
int cur=t;
while(cur != -1){
path.push_back(cur);
cur = p[cur];
}
reverse(path.begin(), path.end());
return path;
}
This is our code, we believe we have to modify it but we really don't know where.
Currently, you are only saving/retrieving one of the shortest paths that you happen to find. Consider this example:
4 nodes
0 -> 1
0 -> 2
1 -> 3
2 -> 3
It becomes clear that you cannot have a single p[] value for each position, as in fact the 4th node (3) has 2 previous valid nodes: 1 and 2.
You could thus replace it with a vector<int> p[MAXN]; and work as follows:
if (d[cur] + w_extra < d[next]){
d[next] = d[cur] + w_extra;
p[next].clear();
p[next].push_back(cur);
q.push(dist_node(d[next], next));
}
else if(d[cur] + w_extra == d[next]){
p[next].push_back(cur); // a new shortest way of hitting this same node
}
You will also need to update your findpath() function as it will need to deal with "branches" resulting in several multiple paths, possibly an exponentially huge amount of paths depending on the graph. If you just need to print the paths, you could do something like this:
int answer[MAXN];
void findpath (int t, int depth){
if(t == -1){ // we reached the initial node of one shortest path
for(int i = depth-1; i >= 0; --i){
printf("%d ", answer[i]);
}
printf("%d\n", last_node); // the target end node of the search
return;
}
for(int i = p[t].size()-1; i >= 0; --i){
answer[depth] = p[t][i];
findpath(p[t][i], depth+1);
}
}
Note you'll need to do p[s].push_back(-1) at the beginning of your dijkstra, besides clearing this vector array between cases.