There are 3 activities in this algorithm.

1. Find if there is a cycle

2. Find first node of the cycle

3. Find length of cycle

To find a cycle two pointers move forward. One pointer moves to next node in subsequent turns, while other moves two steps at a time (like a hare-tortoise race). If they both meet before reaching the end we know there is a cycle. Once they meet, if we set first pointer back to start while second remains at where they meet. Now, if we move both pointers one step at a time, they will both intersect again. However, this time they will intersect at the beginning node of the cycle.

The logic behind this is that at this point a has moved k steps and b has moved 2k steps. Both these steps are divisible by length of the cycle. In above example, they meet at node 7, which is 6 steps from start. Similarly b has moved 12 steps from start. Both of these values are divisible by length of the cycle 6.

Once we find the starting node of the cycle, we can find the length by going through the cycle until it comes back to that node.

a = next(x); b = next(next(x)); while (a != b) { a = next (b); b = next(next(b)); }

a = x; while (a != b) { a = next (b); b = next(b); } first = a;

b = next(a); length = 1; while (a != b) { b = next(b); length++; }

]]>

#include <bits/stdc++.h> using namespace std; #define N 8 int link[N]; int size[N]; void setup() { for (int i = 1; i < N; i++) { link[i] = i; size[i] = 1; } } int find(int x) { while (x != link[x]) x = link[x]; return x; } bool same(int a, int b) { return find(a) == find(b); } void unite(int a, int b) { a = find(a); b = find(b); if (size[a] < size[b]) { int tmp = a; a = b; b = tmp; } // swap size[a] += size[b]; link[b] = a; } int main() { setup(); unite(4, 1); cout << "find(1): " << find(1) << endl; cout << "find(4): " << find(4) << endl; unite(4, 7); cout << "find(7): " << find(7) << endl; unite(2, 3); unite(3, 6); unite(3, 8); unite(2, 4); cout << "find(2): " << find(2) << endl; cout << "find(4): " << find(4) << endl; cout << "find(7): " << find(7) << endl; }

find(1): 4 find(4): 4 find(7): 4 find(2): 2 find(4): 2 find(7): 2

]]>

Consider following tree with 1 as root node.

Two maxium lengths of leaf nodes are 1 for node 2 and 1 for node 4. We then add 2 to sum of both, that gives us a value of 4. Therefore diameter of this tree is 4 with 5->2->1->4->7.

Following code presents dynamic programming and recursive methods for calculating lengths of the leaf nodes. It is a good way to see how to represent recursive algorithm into a dynamic programming solution.

#include <bits/stdc++.h> using namespace std; #define N 8 int leaf[N]; int toLeaf(int s, int e, vector<int> adj[N]) { if (adj[s].empty()) { return 0; } else { int maximum = 0; for (auto u: adj[s]) { if (u == e) continue; maximum = max(maximum, toLeaf(u, e, adj)); } return maximum + 1; } } int toLeafDP(int s, int e, vector<int> adj[N]) { if (leaf[s] >= 0) return leaf[s]; else if (adj[s].empty()) { leaf[s] = 0; return leaf[s]; }else { int maximum = 0; for (auto u: adj[s]) { if (u == e) continue; maximum = max(maximum, toLeafDP(u, e, adj)); } leaf[s] = maximum + 1; return leaf[s]; } } int maxLength(int s, int e, vector<int> adj[N]) { int maxLength = 0; if (adj[s].empty()) return 0; else if (adj[s].size() == 1) return 1 + toLeaf(adj[s][0], s, adj); else { int a = 0, b = 0; for (auto u : adj[s]) { if (u == e) continue; int uLeaf = toLeaf(u, s, adj); if (uLeaf > a) { b = a; a = uLeaf; } else if (uLeaf > b) { b = uLeaf; } } maxLength = a + b + 2; } return maxLength; } int maxLengthDP(int s, int e, vector<int> adj[N]) { int maxLength = 0; if (adj[s].empty()) return 0; else if (adj[s].size() == 1) return 1 + toLeafDP(adj[s][0], s, adj); else { int a = 0, b = 0; for (auto u : adj[s]) { if (u == e) continue; int uLeaf = toLeafDP(u, s, adj); if (uLeaf > a) { b = a; a = uLeaf; } else if (uLeaf > b) { b = uLeaf; } } maxLength = a + b + 2; } return maxLength; } int main() { vector<int> adj[N]; adj[0] = {1}; adj[1] = {2, 3, 4}; adj[2] = {5, 6}; adj[4] = {7}; for (int i = 0; i < N; i++) { leaf[i] = -1; } cout << "toLeaf(2): " << toLeaf(2, 2, adj) << endl; cout << "toLeaf(1): " << toLeaf(1, 1, adj) << endl; cout << "maxLength(1): " << maxLength(1, 1, adj) << endl; cout << "toLeafDP(2): " << toLeafDP(2, 2, adj) << endl; cout << "toLeafDP(1): " << toLeafDP(1, 1, adj) << endl; cout << "maxLengthDP(1): " << maxLengthDP(1, 1, adj) << endl; }

toLeaf(2): 1 toLeaf(1): 2 maxLength(1): 4 toLeafDP(2): 1 toLeafDP(1): 2 maxLengthDP(1): 4

]]>

Following is the code.

#include <bits/stdc++.h> using namespace std; #define N 8 int counter[N]; void dfs(int s, int e, vector<int> adj[N]) { counter[s] = 1; for (auto u : adj[s]) { if (u == e) continue; // e is previous node dfs(u, s, adj); counter[s] += counter[u]; } } int main() { vector<int> adj[N]; adj[0] = {1}; adj[1] = {2, 3, 4}; adj[2] = {1, 5, 6}; adj[3] = {1}; adj[4] = {1, 7}; adj[5] = {2}; adj[6] = {2}; adj[7] = {4}; dfs(1, 0, adj); for (int i = 1; i < N; i++) { cout << counter[i] << " "; } cout << endl; }

7 3 1 2 1 1 1

Note: There does not need to be back reference from a child node to its parent. However, in code we make sure we don’t count values from its parent, so it does not make any difference to calculation.

]]>First all distances are filled with information from adjacent list. If node 1 has edge to node 5 with a weight of 9, distance[1][5] and distance[5][1] are both initialized with 9. All other values in distance array for nodes that don’t have neighbors are initialized to INF.

The algorithm then goes through all intermediatory nodes between two nodes, and tries to calculate a shorter path. If a shorter path is found, the distance array value is updated. Following is the code.

#include <bits/stdc++.h> using namespace std; #define INF 9999 int main() { int n = 6; vector<tuple<int,int>> alt[n]; alt[1].push_back({2, 5}); alt[1].push_back({4, 9}); alt[1].push_back({5, 1}); alt[2].push_back({3, 2}); alt[2].push_back({1, 5}); alt[3].push_back({4, 6}); alt[4].push_back({5, 2}); alt[5].push_back({4, 2}); int adj[n][n]; for (int i = 0; i < n; i++) { for (int j = 0; j < n; j++) { adj[i][j] = 0; } } for (int i = 1; i < n; i++) { for (auto u : alt[i]) { tuple<int,int> t = u; int j = std::get<0>(u); int d = std::get<1>(u); adj[i][j] = d; adj[j][i] = d; } } int distance[n][n]; for (int i = 1; i < n; i++) { for (int j = 1; j < n; j++) { if (adj[i][j]) { distance[i][j] = (int)adj[i][j]; distance[j][j] = (int)adj[j][i]; } else { distance[i][j] = INF; } } } for (int k = 1; k < n; k++) { for (int i = 1; i < n; i++) { for (int j = 1; j < n; j++) { distance[i][j] = min(distance[i][j], distance[i][k] + distance[k][j]); } } } for (int i = 1; i < n; i++) { for (int j = 1; j < n; j++) { cout << distance[i][j] << "\t\t"; } cout << endl; } }

References

Competitive Programmer’s Handbook

]]>Note: To make a priority queue that has least distance negative distance is pushed, so that node with highest value is pushed to top (negatively). Which translates to smallest item being at top. Below is the source code.

#include <bits/stdc++.h> #define INF 999999 using namespace std; void dijkastra(vector<tuple<int,int>> adj[], int n, int distance[], int x) { queue<tuple<int,int>> q; bool processed[n]; for (int i = 1; i < n; i++) { distance[i] = INF; processed[i] = false; } distance[x] = 0; q.push(make_tuple(0,x)); while (!q.empty()) { int node = std::get<1>(q.front()); q.pop(); if (processed[node]) continue; processed[node] = true; for (auto a : adj[node]) { int b = std::get<0>(a); int w = std::get<1>(a); if (distance[node] + w < distance[b]) { distance[b] = distance[node] + w; q.push({-distance[b], b}); // make priority queue by pushing negative value } } } } int main() { int n = 6; int distance[n]; vector<tuple<int,int>> alt[n]; alt[1].push_back({2, 5}); alt[1].push_back({4, 9}); alt[1].push_back({5, 1}); alt[2].push_back({3, 2}); alt[2].push_back({1, 5}); alt[3].push_back({4, 6}); alt[4].push_back({5, 2}); alt[5].push_back({4, 2}); dijkastra(alt, n, distance, 1); cout << "dijkastra: " << endl; for (int i = 1; i < n; i++) { cout << distance[i] << " "; } cout << endl; } // dijkastra: // 0 5 7 3 1

References

Competitive Programmer’s Handbook

]]>Following is the source code.

#include <bits/stdc++.h> #define INF 999999 using namespace std; typedef vector<tuple<int,int,int>> tuple_list; void bellmanford(int distance[], int n, tuple_list edges, int source_node) { for (int i = 1; i < n; i++) { distance[i] = INF; } distance[source_node] = 0; for (int i = 1; i < n; i++) { // n rounds for (auto e : edges) { int a,b,w; tie(a,b,w) = e; if (distance[b] > distance[a] + w) { distance[b] = distance[a] + w; } } } } int main() { tuple_list list; list.push_back(make_tuple(1,2,5)); list.push_back(make_tuple(1,4,9)); list.push_back(make_tuple(1,5,1)); list.push_back(make_tuple(2,3,2)); list.push_back(make_tuple(2,1,5)); list.push_back(make_tuple(3,4,6)); list.push_back(make_tuple(4,5,2)); list.push_back(make_tuple(5,4,2)); int n = 6; int distance[n]; bellmanford(distance, n, list, 1); for (int i = 1; i < n; i++) { cout << distance[i] << " "; } cout << endl; } // 0 5 7 3 1

Note: We ignore index 0 for distance array.

]]>The idea is to store the array values in second half of the tree, and using that store value corresponding to the operation supported in its parent. For a node k its parent is at k/2. For node k, 2 * k and 2 * k + 1 are its children node indices. Using this information we can build and query segment tree. It is obvious from these rules, that the operation are performed in O(logn). Note, even nodes are left child and odd nodes are right child. Following is the source code for sum query.

#include <bits/stdc++.h> using namespace std; void add(int k, int x, int n, int tree[]) { k = k + n; tree[k] += x; k /=2; while (k > 0) { tree[k] = tree[2 * k] + tree[2 * k + 1]; k/=2; } } int sum(int a, int b, int n, int tree[]) { a = a + n; b = b + n; int s = 0; while (a <= b) { if (a % 2 == 1) { s+= tree[a]; a++;} if (b % 2 == 0) { s+= tree[b]; b--;} a/=2; b/=2; } return s; } int main() { int arr[] = {2, 1, 1, 3, 2, 3, 4, 5, 6, 7, 8, 9}; int n = 12; int tree[24] = {0}; for (int i = 0; i < n; i++) { add(i, arr[i], n, tree); } cout << sum(2, 7, n, tree) << endl; cout << sum(0, 11, n, tree) << endl; cout << sum(6, 8, n, tree) << endl; } // 18 // 51 // 15

References

Competitive Programmer’s Handbook

]]>The tree data structure is maintained by updating or quering in accordance with its parent/children. To traverse from current node to parent or child number that corresponds to last set bit is extracted and added or subtracted accordingly.

Here is the formula

index = index – (index & (-index)) // go to parent

index = index + (index &(-index)) // go to children

E.g If current index is 10 = 1010 in binary.

-index = 2s complement of index = ~(index) + 1 = complement of index + 1

-index = ~(1010) + 1. In 8bit system it would be 11110101 + 1 = 11110110

index & (-index) = 00001010 & 11110110 = 00000010

00000010 = 2 in decimal

If we add 2 to 10 it becomes 12 = 1100

If we subtract 2 from 10 it becomes 8 = 1000

These are the next indices the code travels to update or get the values.

With this setup, if we need to get sum of first 12 numbers, we can get value at 12, jump to 10, add that value, then jump to 8, and get that value, after that next jump will be at 0, which only contains dummy value. In this way in O(logn), we can add all the values in that range. Below is the code.

#include <bits/stdc++.h> using namespace std; int getSum(int index, int tree[]) { index = index + 1; int sum = 0; while (index > 0) { sum = sum + tree[index]; index = index - (index & (-index)); // remove last set bit to go to parent } return sum; } void update(int index, int n, int val, int tree[]) { index = index + 1; while (index <= n) { tree[index] = tree[index] + val; index = index + (index & (-index)); // add set bit to go to children } } int main() { int arr[] = {2, 1, 1, 3, 2, 3, 4, 5, 6, 7, 8, 9}; int n = 12; int tree[13] = {0}; for (int i = 0; i < n; i++) { update(i, n, arr[i], tree); } cout << getSum(5, tree) << endl; cout << (getSum(7, tree) - getSum(3-1, tree)) << endl; } // 12 // 17

References

https://www.geeksforgeeks.org/binary-indexed-tree-or-fenwick-tree-2/

]]>

In 8 queen problem, we try to place 8 qeens in a board, so that none of the queens attack each other. Any queen placed in same diagonal, rows or columns attack each other. This is what we avoid through our backtracking solution. Since it is a complete search problem, if the input size is bigger, the computation can get out of hand pretty quickly.

For a 4×4 board and 4 queens there are only 2 solutions. {3,1,4,2} and {2,4,1,3}. These are rows where the queens are placed in each column. Following code prints all the valid positions for 8 queens for a 8×8 board. Change the constant N to 16 and n to 4, to see solution for a 4×4 board.

#include <bits/stdc++.h> #define N 64 using namespace std; int n = 8; int counter = 0; int col[N], diag1[N], diag2[N]; void printcolumn() { for (int i = 0; i < n; i++) { cout << col[i] << " "; } cout << endl; } void search(int y) { if (y == n) { // success counter++; printcolumn(); return; } for (int x = 0; x < n; x++) { if (col[x] || diag1[x+y] || diag2[x-y+n-1]) continue; col[x] = y+1; diag1[x+y] = diag2[x-y+n-1] = 1; search(y+1); col[x] = diag1[x+y] = diag2[x-y+n-1] = 0; } } int main() { search(0); cout << counter << endl; }

Note: This solution is extracted from Competitive Programmer’s Handbook by Antti Laaksonen.

We use col, diag1 and diag2 to track if a column, and both diagonals are already filled. The input y makes sure we don’t put elements in same row. Using a 4×4 box is a pretty good way to trace how backtracking works. For a 8×8 board it generates 92 solutions. E.g. {1 7 5 8 2 4 6 3, 3 6 4 2 8 5 7 1}

]]>