What's the maximum number of nodes on a path? - c++

I'm having the following problem:
There are a lot of nodes and several of them are already connected, but not all. We have to add connections such that each node is connected with any other(not neccessary directly). We do not want to change any of the existing connections.
The nodes have to be connected with the least amount of lines (the current connections already follow this rule). Also a path from one node to another must pass through the least amount of other nodes. We want to know the maximum number of nodes on any path, when everything is connected in an optimal way.
Input:
The following data is given by user input:
• You get two integers: the number 1 ≤ p ≤ 1.000.000 of nodes and the
number 0 ≤ l ≤ p − 1 of existing connections.
• Then l lines with each two integers a and b between 0 and p − 1 (inclusive), denoting the endpoints of a connection.
Output:
The output should be an integer that represents the maximum number of nodes on any path.(so without the beginning and endpoints)
So for example when we have as input p = 6, l = 4 and the connections 2-0, 1-0, 5-3 and 4-3 the output should be 2.
I already wrote a program in c++ that does the following:
int main(){
int p, l;
cin >> p >> l;
for (int i = 0; i < l; i++){
int a, b;
cin >> a >> b;
// store the connection a,b somehow
}
// solve the problem
cout << answer << endl;
}
I thought of storing the connections in an p - 1 times p - 1 array, with a 1 if the line exists and 0 otherwise. Furtermore I need something to decide how to make connections in an optimal way and compute the maximum amount of nodes on each path. I'm only allowed to use the standard library of C++.
Could someone please help me with this? Thanks in advance!

This sounds like a basic algorithms homework...
Given your existing graph, find the maximum path. Unless you have only two nodes, this will be your answer.
Connect all your new nodes to any node that is not a leaf node of your maximum path.
(Lines that connect nodes are called "edges".)
Let me know if I have misunderstood your problem.
edit
Here is a simple graph.
The maximal path is (a,b,c) [which is the same as (c,b,a) -- we'll always order the two leaves so that the smallest comes first].
(a)--(b)--(c)
I can find it by picking any leaf node -- a node with exactly 1 edge -- and finding my way to another leaf node.
The furthest leaf node will be the longest/maximal path from that node.
Do it again from the leaf node you just found, and you will have the longest/maximal path for the entire graph.
Let's examine how that works with a new graph:
(a)--(b)--(c)--(d)--(e)--(f)
|
(s)
I'm going to start at node (s). If I find the longest path from it I will find node (f). Node (f) must be one of the endpoints on the longest path in the graph. (I'll leave it to you to think about why.)
Now, I start again at node (f). The longest path from (f) leads to (a). I now have the longest path in the graph: (a,b,c,d,e,f).
Here is another graph:
(a)--(b)--(c)
|
(d)
There are a number of longest paths to choose from. (a,b,c), (a,b,d), and (c,b,d). What matters is that they all exist and have the same length.
Now, to which node should I connect a new node (e) so that I don't change the longest path? Easy:
(e)
|
(a)--(b)--(c)
|
(d)
You can guarantee this by only attaching a new node to nodes that are not leaf nodes.
As for your question about how to represent the graph, your idea will work fine, but remember, you have p nodes, not p-1. So, for example, I can represent my 3-node graph as:
from
a b c
a 0 1 0
to b 1 0 1
c 0 1 0
Notice the columns: a only leads to one other node. Likewise, c only leads to one other node.
However, b's column shows that b leads to two other nodes (which is more than one).
Hence, a and c are leaves; b is not.
If I add a new node, I will want to connect it only to nodes that have more than one node already:
a b c d a b c d
a 0 1 0 0 a 0 1 0 0
b 1 0 1 0 --> b 1 0 1 1
c 0 1 0 0 c 0 1 0 0
d 0 0 0 0 d 0 1 0 0
Hope this helps.

Related

Efficient algorithms to check if a binary maze is solvable with restricted moves

I am given a problem to generate binary mazes of dimensions r x c (0/false for blocked cell and 1/true for free cell). Each maze is supposed to be solvable.
One can move from (i, j) to either (i + 1, j)(down) or (i, j + 1)(right). The solver is expected to reach (r - 1, c - 1)(last cell) starting from (0, 0)(first cell).
Below is my algorithm (modified BFS) to check if a maze is solvable. It runs in O(r*c) time complexity. I am trying to get a solution in better time complexity. Can anyone suggest me some other algorithm?? I don't want the path, I just want to check.
#include <iostream>
#include <queue>
#include <vector>
const int r = 5, c = 5;
bool isSolvable(std::vector<std::vector<bool>> &m) {
if (m[0][0]) {
std::queue<std::pair<int, int>> q;
q.push({0, 0});
while (!q.empty()) {
auto p = q.front();
q.pop();
if (p.first == r - 1 and p.second == c - 1)
return true;
if (p.first + 1 < r and m[p.first + 1][p.second])
q.push({p.first + 1, p.second});
if (p.second +1 < c and m[p.first][p.second + 1])
q.push({p.first, p.second + 1});
}
}
return false;
}
int main() {
char ch;
std::vector<std::vector<bool>> maze(r, std::vector<bool>(c));
for (auto &&row : maze)
for (auto &&ele : row) {
std::cin >> ch;
ele = (ch == '1');
}
std::cout << isSolvable(maze) << std::endl;
return 0;
}
Recursive Solution:
bool exploreMaze(std::vector<std::vector<bool>> &m, std::vector<std::vector<bool>> &dp, int x = 0, int y = 0) {
if (x + 1 > r or y + 1 > c) return false;
if (not m[x][y]) return false;
if (x == r - 1 and y == c - 1) return true;
if (dp[x][y + 1] and exploreMaze(m, dp, x, y + 1)) return true;
if (dp[x + 1][y] and exploreMaze(m, dp, x + 1, y)) return true;
return dp[x][y] = false;
}
bool isSolvable(std::vector<std::vector<bool>> &m) {
std::vector<std::vector<bool>> dp(r + 1, std::vector<bool>(c + 1, true));
return exploreMaze(m, dp);
}
Specific need:
I aim to use this function many times in my code: changing certain point of the grid, and then rechecking if that changes the result. Is there any possibility of memoization so that the results generated in a run can be re-used? That could give me better average time complexity.
If calling this function many times with low changes there's a data structure called Link-Cut tree which supports the following operations in O(log n) time:
Link (Links 2 graph nodes)
Cut (Cuts given edge from a graph)
Is Connected? (checks if 2 nodes are connected by some edges)
Given that a grid is an implicit graph we can first build Link-Cut tree, in O(n*m*log(n*m)) time
Then all updates (adding some node/deleting some node) can be done by just deleting/adding neighboring edges which will only take O(log(n*m)) time
Though I suggest optimizing maze generation algorithm instead of using this complicated data structure. Maze generation can be done with DFS quite easily
The problem you are looking at is known as Dynamic Connectivity and as #Photon said, as you have an acyclic graph one solution is to use Link-cut tree. Another one is based on another representation as Euler tour.
You cannot go below O(r*c) in the general case because, with any pathfinding strategy, there is always a special case of a maze where you need to traverse a rectangular subregion of dimensions proportional to r and c before finding the correct path.
As for memoization: there is something you can do, but it might not help that much. You can build a copy of the maze but only keeping the valid paths, and putting in each cell the direction towards the previous and next cells, as well as the number of paths that traverse it. Let me illustrate.
Take the following maze, and the corresponding three valid paths:
1 1 1 0 1 1 1 1 0 0 1 1 0 0 0 1 1 0 0 0
0 1 1 1 1 0 0 1 1 0 0 1 1 1 0 0 1 0 0 0
0 1 0 1 0 0 0 0 1 0 0 0 0 1 0 0 1 0 0 0
1 1 0 1 0 0 0 0 1 0 0 0 0 1 0 0 1 0 0 0
0 1 1 1 1 0 0 0 1 1 0 0 0 1 1 0 1 1 1 1
You can build what I'll call the forward direction grid (FDG), the backward direction grid (BDG), and the valuation grid:
R B D N N B L L N N 3 3 1 0 0
N B R D N N U B L N 0 2 2 2 0
N D N D N N U N U N 0 1 0 2 0
N D N D N N U N U N 0 1 0 2 0
N R R R B N U L B L 0 1 1 3 3
R = right, D = down, L = left, U = up, B = both, and N = none.
The FDG tells you, in each cell, in what direction is the next cell on a valid path (or if both are). The BDG is the same thing in reverse. The valuation grid tells you how many valid paths contain each cell.
For convenience, I'm putting a B at the destination in the direction grids. You can see it as if the goal was to exit the maze, and to do so, you can go in either direction from the final cell. Note that there are always the same number of B cells, and that it's exactly the number of valid paths.
The easiest way to get these grids is to build them during a depth-first search. In fact, you can even use the BDG for the depth-first search since it contains backtracking information.
Now that you have these, you can block or free a cell and update the three grids accordingly. If you keep the number of valid paths separately as well, you can update it at the same time and the condition "the maze is solvable" becomes "the number of valid paths is not zero". Also note that you can combine both direction grids, but I find them easier to grasp separately.
To update the grids and the number of valid paths, there are three cases:
(A) you blocked a cell that was marked N; you don't need to do anything.
(B) you blocked a cell that was not marked N, so previously part of at least one valid path; decrement the number of valid paths by the cell's value in the valuation grid, and update all three grids accordingly.
(C) you freed a cell (that was necessarily marked N); update all three grids first and then increment the number of valid paths by the cell's new value in the valuation grid.
Updating the grids is a bit tricky, but the point is that you do not need to update every cell.
In case (B), if the number of valid paths hits zero, you can reset all three grids. Otherwise, you can use the FDG to update the correct cells forward until you hit the bottom-right, and the BDG to update the correct ones backward until you hit the top-left.
In case (C), you can update the direction grids first by doing a depth-first search, both forward and backward, and backtrack as soon as you hit a cell that isn't marked N (you need to update this cell as well). Then, you can make two sums of the values, in the valuation grid, of the cells you hit: one going forward and one going backward. The number of paths going through the new cell is the product of these two sums. Next, you can update the rest of the valuation grid with the help of the updated direction grids.
I would imagine this technique having an effect on performance with very large mazes, if the updates to the maze itself do not create or break too many paths every time.

Iterate by level over right most element of a heap

Is there a way I can create a for loop such that, given any starting location the loop will subsequently iterate through the right-most element of each level? Given some heap:
If you were inside a make_heap function, you may start at (n-2)/2) which would be the node denoted by the red twelve.
Now, given some start location (n-2)/2, is it possible to iterate such that the subsequent values of the loop will be 6 -> 2 -> 0 (array location of the right most elements above the initial level, which is the red number minus one) which correspond to 14 -> 24 -> 25.
My initial implementation looks like
using std::size_t;
size_t n = last - first; // size of heap
for(size_t start = (n-2)/2;
start > 0;
start = (size_t)pow(2, (size_t)log2(start)-1))
{
std::cout << start << std::endl;
}
My thinking was that start is equal to 2log2(start)-1, which means the previous level.
However this only yields 11, 4, 2, 1 (add one for the corresponding node location in red). It in theory should be 11, 6, 2, 0. Any ideas?
Assuming your indices are 1-based, it is straight forward to compute the parent and the child nodes of a node given its index n:
you get the parent node using n / 2
you get the left child node using n * 2
you get the rigth child node using n * 2 + 1
Since arrays in C++ are 0-base you may need to strategically add/substract 1 to convert between node and array indices.
To get to the right children of the the parent nodes you'd keep the index p of the current parent node, replacing it using p = p / 2 in each direction and access the node at p * 2 + 1. Of course, if make_heap() is anything like std::make_heap() it doesn't need to do anything like that. It merely needs to "bubble up" the new node while its parent is bigger the node.

Count the number of paths in DAG with length K

I have a DAG with 2^N nodes, with values from 0 to 2^N-1. There is edge from x to y if x < y and x (xor) y = 2^p, x and y being the node values and p a non-negative integer.
Since N can be as large as 100000, generating the graph and than proceeding with the counting would take much computational time. Is there any way to count the paths with certain length K (K being the number of edges between two nodes), differently stated, is there an equation of some sort for this kind of counting?
Thanks in advance
Michael's got some good insights, but I'm not sure I follow his entire argument. Here's my solution.
Let's say N=4, K=2. So the nodes range from 0 (00002) to 15 (11112).
Now let's consider node 2 (00102). There's an edge from 2 to 3 (00112) because 2 < 3 and xor(2,3) = 1 = 20. There's also an edge from 2 to 6 because 2 < 6 and xor(2,6) = 4 = 22. And there's an edge from 2 to 10 because 2 < 10 and xor(2,10) = 8 = 23.
To generalize: for any x, consider all of the 0 bits in x. By flipping any of the 0 bits to 1, you get a number y that's larger than x and differs from x by one bit. So there's an edge from x to that y.
The number of 1 bits in x is typically called the population count of x. I'll use pop(x) to mean the population count of x.
We're dealing with N-bit numbers (when we include leading zeroes), so the number of 0 bits in x is N - pop(x).
Let's use the term “j-path” to mean a path of length j. We want to count the number of K-paths.
Every node x has N - pop(x) outgoing edges. Each of these edges is a 1-path.
Let's consider node 5 (01012). Node 5 has an edge to 7 (01112), and node 7 has an edge to 15 (11112). Node 5 also has an edge to 13 (11012), and node 13 has an edge to 15 (11112). So there are two 2-paths out of node 5: 5-7-15 and 5-13-15.
Next let's look at node 2 (00102) again. Node 2 has an edge to 3 (00112), which has edges to 7 (01112) and 11 (10112). Node 2 also has an edge to node 6 (01102), which has edges to 7 (01112) and 14 (11102). Finally, node 2 has an edge to node 10 (10102), which has edges to 11 (10112) and 14 (11102). In all, there are six 2-paths out of node 2: 2-3-7, 2-3-11, 2-6-7, 2-6-14, 2-10-11, and 2-10-14.
The pattern is that, for any node x with z bits set to zero, where z ≥ K, there are some K-paths out of x. To find a K-path out of x, you pick any K of the zero bits. Flipping those bits to 1, one by one, gives you the path. You can flip the bits in any order you want; each order gives a different path.
When you want to pick k items, in a specific order, from a set of n items, that's called an ordered sample without replacement, and there are n! / (n-k)! ways to do it. This is often written nPk, but it's easier to type P(n,k) here.
So, the nodes that have exactly 2 zero bits have P(2,2) = 2! / (2-2)! = 2 2-paths out of them. (Note that 0! = 1.) The nodes that have exactly 3 zero bits have P(3,2) = 3! / 1! = 6 2-paths out of them. The node that has exactly 4 zero bits has P(4,2)= 4! / 2! = 12 2-paths out of it. (Since I'm using N=4 for the example, there is only one node with exactly 4 zero bits, which is node 0.)
But then we need to know, how many nodes have exactly 2 zero bits? Well, when there are n items to choose from, and we want to choose k of them, and we don't care about the order of the chosen items, that's called an unordered sample without replacement, and there are n! / (k! (n-k)!) ways to do it. This is called “n choose k”, and it's usually written in a way that I can't reproduce on stack overflow, so I'll write it as C(n,k).
For our example with N=4, there are C(4,2) = 6 nodes with exactly 2 bits set to zero. These nodes are 3 (00112), 5 (01012), 6 (01102), 9 (10012), 10 (10102), and 12 (11002). Each of these nodes has P(2,2) 2-paths out of it, so that means there are C(4,2) * P(2,2) = 6 * 2 = 12 2-paths out of nodes with exactly two 0 bits.
Then there are C(4,3) = 4 nodes with exactly 3 bits set to zero. These nodes are 1 (00012), 2 (00102), 4 (01002), and 8 (10002). Each of these nodes has P(3,2) 2-paths out of it, so there are C(4,3) * P(3,2) = 4 * 6 = 24 2-paths out of nodes with exactly three 0 bits.
Finally, there is C(4,4) = 1 node with exactly 4 bits set to zero. This node has P(4,2) = 12 2-paths out of it.
So the total number of 2-paths when N=4 is C(4,2)*P(2,2) + C(4,3)*P(3,2) + C(4,4)*P(4,2) = 12 + 24 + 12 = 48.
For general N and K (where K ≤ N), the number of K-paths is the sum of C(N,z) * P(z,K) for K ≤ z ≤ N.
I can type that into Wolfram Alpha (or Mathematica) like this:
Sum[n!/(z! (n - z)!) z!/(z - k)!, {z, k, n}]
And it simplifies it to this:
2^(n-k) n! / (n-k)!
The stated problem seems to be equivalent to this one:
Consider the set of all possible binary strings of length N. Consider operation Fi that flips i-th bit from 0 to 1. For strings x & y denote |x| the number of set bits, x
It's easy to see that one can obtain y from x by a series of exactly K operations Fi if and only if (x,y) is K-admissible. Moreover, if we fix x and sum up over all y such that (x,y) is K-admissible we get (N-|x|)!
Finally, we need to sum up over all x with |x|<=(N-K). For a given choice of |x| we have N!/(N-|x|)!|x|! possible choices of x. Combine with the above and you get that for the given |x| there are N!/|x|! possible paths.
Denote |x|=M, with M from 0 to N-K, and your answer is the sum over all M of N!/M!

Finding the location of a parent node in a binary tree

So I need help coming up with an expression that will always give me the location of a child's parent node in a binary tree. Here is an example of a problem my teacher will put on our exam:
"Consider a complete binary tree with exactly 10,000 nodes, implemented with an array starting at index 0 . The array is populated in order by extracting elements from the tree one level at a time from left to right. Suppose that a node has its value stored in location 4999. Where is the value stored for this node’s parent?"
My teacher did not tell us how to solve a problem like this. She just said "Draw a binary tree and find a pattern." I did just that but i could not come up with anything! please help. thanks.
The following is entirely using integer division. I.e. fractional remainders are dropped. For any given node index N, the children of that node will always be in locations 2N+1 and 2(N+1) in the same array.
Therefore, The parent of any node N > 0 in such an array will always be at index (N-1)/2.
Parent to Child Examples:
Parent 0: children 1,2
Parent 1: children 3,4
Parent 2: children 5,6
Parent 3: children 7,8
etc...
Child to Parent Examples:
Child 8 : Parent = (8-1)/2 = 7/2 = 3
Child 7 : Parent = (7-1)/2 = 6/2 = 3
Child 6 : Parent = (6-1)/2 = 5/2 = 2
Child 5 : Parent = (5-1)/2 = 4/2 = 2
So for your problem:
(4999-1)/2 = 4998/2 = 2499
Note: remember this, since you'll be using it extensively when you start coding array-based heap-sort algorithms.
Thanks for all your help guys. And I found the answer to my question!
The general algorithm for finding the location of the parent node is:
[i + (root - 1)] / 2 where i is the location of the given node and root is the location of the root. So in the given problem above the root starts at position 0. so the equation to find the parent node of any node is [i + (0 - 1)] / 2 = (i - 1) / 2
Now let's say the root started at position 3, then the equation would be [i + (3 - 1)] / 2
= (i + 2) / 2!!!! This is the algorithm I needed. Most of you helped me solve the one problem i provided but i actually needed the general solution for a binary tree whose root can start at any postions; not just at zero
It seems this is how the array elements map back to tree based on array indices
0
1 2
3 4 5 6
If so, then the parent of index n is at floor( (n - 1) / 2 ) (for n != 0)
If you do the log2 of the number requested (4999) and take the integer part it will give you the closest power of two to the number (12). It is 2^12 = 4096.
The parent of the nodes between 4096 and 2^13 - 1, are the ones between 2^11 and 2^12 - 1. And for each pair of nodes in the first range you have its parent in the second. So you can map them taking the integer part of the half of the difference (4999 - 4096) and adding it to the parent range start (2048).
So you will have floor of 903 / 2, and add it to 2048, getting 2499.
Note that I didn't make a precise calculation, take the strategy of the answer not the results.
You can put this algorithm in a mathematical expression, with a little work.
Hope it helps!
The parent node is at n/2 if n is even.
It is at (n-1)/2 if n is odd.
So you can remember it as math.ceil((n-1)/2)

graphs divisibility

Given a simple undirected graph containing N vertices numbered 1 to N, each vertex containing a digit from {1,2,..7}. Starting at the vertex 1 with an empty string S, we travel through some vertices (with no limitations) to the vertex N. For every vertex on the way, we add the respective digit to the right of the string S. At last we get S as a decimal integer. You are requested to find such a way satisfying S is divisible by all of its digits, and the sum of digits of S must be as small as possible.
Input
There are several test cases (fifteen at most), each formed as follows:
The first line contains a positive integer N (N ≤ 100).
The second line contains N digits (separated by spaces), the i-th digit is the value of the i-th vertex.
N last lines, each contains N values of {0, 1} (separated by spaces), the j-th value of the i-th line is equal to 1 if there is an edge connecting two vertices (i, j), otherwise 0.
The input is ended with N = 0.
Output
For each test case, output on a line the minimum sum of digits found, or -1 if there's no solution.
example
Input:
4
1 2 1 4
0 1 1 1
1 0 0 1
1 0 0 1
1 1 1 0
Output:
7
please guide me
there can be self loops and cycles such that node 1 and node N can be visted any number of times
If given graph is transformed to some other graph, where cycles are not allowed, this problem can be solved with Dijkstra's algorithm.
To do this, let's start with string divisibility by 7. Look at this sequence: 1, 10, 100, ... (mod 7). Since 7 is a prime number, 107-1 = 1 (mod 7) because of Fermat's little theorem. Which means 1, 10, 100, ... (mod 7) sequence is periodic and period is 6. This will be used to transform the graph and also this allows to recursively compute Sn (mod 7) using Sn-1 (mod 7): Sn = Sn-1 + 10n%6 * n_th_digit (mod 7).
It's necessary to start shortest path search from node N because this path may be ended at one of the several nodes of the transformed graph. Also this allows to determine quickly (using first 2 nodes of the path), if it is allowed to visit node "5", node"4", and other "even" nodes.
Algorithm's open set (the priority queue) should contain the priority itself (sum of digits) as long as 3 additional bits and 3 remainders: is "4" allowed, is "3" visited, is "7" visited, S % 3, S % 7, and S.length % 6.
Graph should be transformed as follows. Each vertex is expanded to 3 vertexes, one is allowed only for S%3==0, others - for S%3==1 and S%3==2. Then each vertex is expanded to 7 (for S%7), and then each vertex is expanded to 6 (for S.length % 6). It is possible to fit all these expansions to the original graph: just add a 3D array (size 3*7*6) of back-pointers to each node. While searching for the shortest path, the non-empty back-pointers determine algorithm's closed set (they disallow cycles). When shortest path is found, back-pointers allow to reconstruct the sequence of nodes in this path. And the moment when shortest path is found is determined by visiting node 1 with (node_3_not_visited || S%3==0) && (node_7_not_visited || S%7==0).
First mathematically find the LCM of the numbers given in the set.
lemme paraphrase the scenario .... given a set of numbers... find the LCM then traverse the vetices in such a way that the their path makes the number .Since its LCM it is number whose sum is mininum
For set {0,1,2,3,4} LCM is 12 so travers from 1 to 2
for set {0,1,2,3,4,5,6,7} LCM is 420..(I think i am right)
Use the A* search algorithm, where the "cost" is the sum of the digits, and divisibility determines which edges you can traverse.