Wikipedia's pseudocode for Breadth-first search: How could n's parent be u if "n is adjacent to u"? - pseudocode

Studying the Breadth-first search algorithm, I encountered the following pseudo-code:
1 Breadth-First-Search(G, v):
2
3 for each node n in G:
4 n.distance = INFINITY
5 n.parent = NIL
6
7 create empty queue Q
8
9 v.distance = 0
10 Q.enqueue(v)
11
12 while Q is not empty:
13
14 u = Q.dequeue()
15
16 for each node n that is adjacent to u:
17 if n.distance == INFINITY:
18 n.distance = u.distance + 1
19 n.parent = u
20 Q.enqueue(n)
My question is regarding line 19 (n.parent = u):
How could n's parent be u if "n is adjacent to u"?

A parent is by definition adjacent to its children, they wouldn't be children without the connection. But that's not what this is about. The parent pointers are something completely separate from the structure of the graph, it's something new you're building up that keeps track of from where a node was first reached.

Related

Find the number of all possible path in a grid, from (0, 0) to (n, n)

I don't know how to find the number of all possible path in a grid, from a Point A to a Point B.
The point A is on (0,0) and the point B is on (n,n).
A can move up, down, right, and left, and can't move on visited points.
While A moving, A(x,y) = (x,y|(0=<x=<n)∩(0=<y=<n)).
You can solve this problem with recursive backtracking, but there's another approach which I think is more interesting.
If we work out the first few cases by hand we find that:
A 1x1 square has 1 path
A 2x2 square has 2 paths
A 3x3 square has 12 paths
If we then go to OEIS (the Online Encyclopedia of Integer Sequences) and put in the search phrase "1,2,12 paths", the very first result is A007764 which is entitled "Number of nonintersecting (or self-avoiding) rook paths joining opposite corners of an n X n grid".
Knowing what integer sequence you're looking for unlocks significant mathematical resources, including source code to generate the sequence, related sequences, and best-known values.
The known values of the sequence are:
1 1
2 2
3 12
4 184
5 8512
6 1262816
7 575780564
8 789360053252
9 3266598486981642
10 41044208702632496804
11 1568758030464750013214100
12 182413291514248049241470885236
13 64528039343270018963357185158482118
14 69450664761521361664274701548907358996488
15 227449714676812739631826459327989863387613323440
16 2266745568862672746374567396713098934866324885408319028
17 68745445609149931587631563132489232824587945968099457285419306
18 6344814611237963971310297540795524400449443986866480693646369387855336
19 1782112840842065129893384946652325275167838065704767655931452474605826692782532
20 1523344971704879993080742810319229690899454255323294555776029866737355060592877569255844
21 3962892199823037560207299517133362502106339705739463771515237113377010682364035706704472064940398
22 31374751050137102720420538137382214513103312193698723653061351991346433379389385793965576992246021316463868
23 755970286667345339661519123315222619353103732072409481167391410479517925792743631234987038883317634987271171404439792
24 55435429355237477009914318489061437930690379970964331332556958646484008407334885544566386924020875711242060085408513482933945720
25 12371712231207064758338744862673570832373041989012943539678727080484951695515930485641394550792153037191858028212512280926600304581386791094
26 8402974857881133471007083745436809127296054293775383549824742623937028497898215256929178577083970960121625602506027316549718402106494049978375604247408
27 17369931586279272931175440421236498900372229588288140604663703720910342413276134762789218193498006107082296223143380491348290026721931129627708738890853908108906396
You can generate the first few terms yourself on paper or via recursive backtracking, per the other answer.
I would suggest solving this with naive recursion.
Keep a set visted of places that you have visited. And in pseudo-code that is deliberately not any particular language:
function recursive_call(i, j, visited=none)
if visited is none then
visited = set()
end if
if i = n and j = n then
return 1
else if (i, j) in visited or not in grid then
return 0
else
total = 0
add (i, j) to visited
for direction in directions:
(new_i, new_j) = move(i, j, direction)
total += recursive_call(new_i, new_j, visited)
remove (i, j) from visited
return total
end if
end function

Is it possible to determine the hop-count when performing Dijkstra?

Thank the codes from #trincot I can modify the Dijkstra to obtain the shortest path between a given source node and destination node.
Moreover, I tried to count the hop when performing the Dijkstra to find the shortest path, when the hop-count exceeds the pre-defined Max_hop, the Dijkstra will be terminated, but I was failed.
Hop is defined as the (N - 1), where N is the number of vertices contained in the shortest paths.
Absolutely, after finding the shortest path, we can easily count the hop number. However, during the Dijkstra's path searching, can we count the hop between a given source and?
from heapq import heappop, heappush
def dijkstra(adjList, source, sink):
n = len(adjList)
parent = [None]*n
heap = [(0,source,0)]
explored_node=[]
hop_count = 0
Max_hop = 8
while heap:
distance, current, came_from = heappop(heap)
if parent[current] is not None: # skip if already visited
continue
parent[current] = came_from # this also marks the node as visited
if sink and current == sink: # only correct place to have terminating condition
# build path
path = [current]
while current != source:
current = parent[current]
path.append(current)
path.reverse()
hop_count -=1
print("Hop count is ",hop_count)
return 1, distance, path
for (neighbor, cost) in adjList[current]:
if parent[neighbor] is None: # not yet visited
heappush(heap, (distance + cost, neighbor, current))
hop_count = hop_count + 1
if hop_count > Max_hop:
print("Terminate")
adjList =[
[],
[[2,3],[4,11],[5,5]],
[[1,3],[3,5],[5,11],[6,7]],
[[2,5],[6,3]],
[[1,11],[5,15],[7,9]],
[[1,5],[2,11],[6,3],[7,6],[8,3],[9,9]],
[[2,7],[3,3],[5,3],[9,10]],
[[4,9],[5,6],[8,1],[10,11],[11,8]],
[[5,3],[7,1],[9,9],[11,11]],
[[5,9],[6,10],[8,9],[11,3],[12,8]],
[[7,11],[13,7],[14,3]],
[[7,8],[8,11],[9,3],[12,8],[14,6]],
[[9,8],[11,8],[15,11]],
[[10,7],[15,3]],
[[10,3],[11,6],[15,9]],
[[12,11],[13,3],[14,9]],
]
flag, dist, path = dijkstra(adjList,1,15)
print("found shortest path {}, which has a distance of {}".format(path, dist))
The graph of adjList is as shown: (the red line is the shortest path from 1 to 15)
I know this is incorrect since when Dijkstra iterates the neighbor, I make hop_cout + 1 that represents the number of explored nodes rather than the hop_count.
In my opinion, there are two significant issues that need to be addressed.
When the shortest distance between a parent_node and a neighbor_node is determined, the hop_count can be added 1. But, Dijkstra finds the shortest path by iterating the neighbor nodes, and the array that stores the shortest distance is updated gradually during path searching. How to determine Dijkstra has already found the shortest distance between a parent_node and a neighbor_node?
Only condition 1 is not enough, even we can know when Dijkstra has found the shortest distance between two nodes, but how do we know whether the neighbor_node will be included in the shortest path between a given source and destination?
In summary, if we want to know the current hop-count during Dijkstra is running, we need to set hop_count +1, When the shortest path from the parent_node to the neighbor_node has been determined, and the neighbor_node will be included to the shortest path from the source to the destination node.
To better define the problem, as shown in this figure, the red line is the shortest path between node 1 and node 15, the shortest path is 1 ->5 ->8 ->7 ->10 ->13 ->15.
When node 2 is explored and the shortest distance between node 1 and
node 2 is determined as 3, the hop_count cannot be added 1 since
node 2 is not contained in the shortest path between 1 and 15.
When node 5 is explored and the shortest distance between node 1 and
node 5 is determined as 5, the hop_count should be added 1 since
node 5 is contained in the shortest path between 1 and 15.
Is my understanding correct? May I hear your idea that "Is it possible to determine the hop-count when performing Dijkstra? "
As the heap will have nodes that represent paths having varying lengths, you cannot hope to use one variable for the hop count. You would need to add the hop count as an additional information in the tuples that you put on the heap, as it is specific to each individual path.
Secondly, you would need to allow that different paths to the same node are allowed to be extended further, as some of these might drop out because of the hop limit, while another may stay under that limit. So concretely, when a more costly path is found to an already visited node, but the number of hops is less, it should still be considered. This means that came_from is not a good structure now (as it only allows one path to pass via a node). Instead we can use a linked list (of back-references) that is included in the heap-element.
NB: I would also make max_hop a parameter to the function:
from heapq import heappop, heappush
def dijkstra(adjList, source, sink, max_hop=8): # make max_hop a parameter
n = len(adjList)
least_hops = [n]*n # Used for deciding whether to visit node via different path
heap = [(0, 0, (source, None))] # came_from is now a linked list: (a, (b, (c, None)))
while heap:
distance, hop_count, chain = heappop(heap) # hop_count is part of tuple
current = chain[0]
if hop_count >= least_hops[current]:
continue # Cannot be an improvement
least_hops[current] = hop_count
if sink and current == sink:
print("Hop count is ", hop_count)
path = []
while chain:
current, chain = chain # Unwind linked list
path.append(current)
return 1, distance, path[::-1]
if hop_count >= max_hop: # no recursion beyond max_hop
print("Terminate")
continue
hop_count += 1 # Adjusted for next pushes unto heap
for neighbor, cost in adjList[current]:
heappush(heap, (distance + cost, hop_count, (neighbor, chain))) # Prepend neighbor
As to your other question:
How to determine Dijkstra has already found the shortest distance between a parent_node and a neighbor_node?
We don't determine this immediately and allow multiple paths to the same node to co-exist. The if in the for loop detects whether the node was already visited and the number of hops to it is not an improvement: this means it had received priority on the heap and had been pulled from it in an earlier iteration of the main while loop, and thus we already have a shortest path to that node. This if prevents us from pushing a useless "alternative" path on the heap: even if the shortest path needs to be rejected later because it cannot stay within the hop limit, an alternative that did not use fewer hops, cannot hope to then stay within the limit either, so it can be rejected now.
There are two questions here, one is how to keep track of the length of the path and the other is terminating the program once the maximum path length is exceeded. Both have quite different answers.
On one hand, you can keep count of how many hops the shortest path has by just getting the length of the path after the algorithm finishes (though it doesn't seem to be what you want). Secondly, you might also keep track of how many hops are required to get from the source to any given node X at an arbitrary iteration, just keep track of the length of the current path from s to a vertex X and update the path-length of the neighbors at the relaxation step. This is greatly covered by #trincot answer which provides code too.
Now, before getting to the program termination part, let me state three useful lemmas that are invariant through Dijkstra Algorithm.
Lemma 1: For every marked vertex, the distance from source to that vertex is a shortest path.
Lemma 2: For every unmarked vertex, the current recorded distance is a shortest path considering only the already visited vertices.
Lemma 3: If the shortest is s -> ... -> u -> v then, when u is visited and it's neighbor's distance updated the distance d(s, v) will remain invariant.
What these lemmas tell us is that:
When node X is marked as visited then: d(s, x) is minimal and the length of the path s->x will remain invariant (from Lemma 1)
Until node X is marked as visited d(s, x) is an estimate and the length of the path s->x is whatever the current path length is. Both values might change. (from Lemma 2)
You can't guarantee that a path of length N is a shortest path nor guarantee that the shortest path has length <= N (From Lemma 3 with a bit of work)
Therefore, if you decide to terminate the program when the path-length from source to sink is greater than a maximum hops number the information obtained can't be guaranteed to be optimal. In particular, any of these may happen at program termination:
The path length is N but there is another path of length N with shorter distance.
The path length is N and there is another path of minor length and shorter distance.
If you want to get the shortest path from source to sink while putting a limit on the path length you should use the Bellman-Ford algorithm instead, which guarantees that at each iteration i all path have length of at most i edges and that this path is shortest with that constraint.
This code is using prioirty queue for dijkstra algorithm.
#include <iostream>
#include <algorithm>
#include <queue>
#include <cstring>
#include <cstdio>
#include <vector>
#define limit 15
using namespace std;
int cost[20001];
vector<int> plist[20001];
const int MaxVal = -1;
vector< vector< pair<int, int> > > arr;
struct node {
pair<int, int> info;
vector<int> path;
};
bool operator < (node a, node b) {
return a.info.first > b.info.first;
}
int main() {
int i, j, k;
int n, m;
int s;
int a, b, c;
cin >> n >> m;
cin >> s;
//arr.reserve(n + 1);
arr.resize(n + 1);
for (i = 1; i <= m; i++) {
cin >> a >> b >> c;
arr[a].push_back({ b, c });
}
for (i = 1; i <= n; i++) {
cost[i] = MaxVal;
}
priority_queue<node, vector<node>> mh;
mh.push(node{ { 0, s }, { } });
while (mh.size() > 0) {
int current = mh.top().info.second;
int val = mh.top().info.first;
auto path = mh.top().path;
mh.pop();
if (cost[current] != MaxVal) continue;//All path would be sorted in prioirty queue. And the path that got out late can't be the shorter path.
cost[current] = val;
path.push_back(current);
if(path.size() > limit) {
//limit exceeded!!
cout << "limitation exceeded!!";
break;
}
plist[current] = path;
for (auto it : arr[current]) {
if (cost[it.first] != MaxVal) continue;
mh.push({ { it.second + val, it.first }, path });
}
}
for (i = 1; i <= n; i++) {
cout << "path to " << i << " costs ";
if (cost[i] == MaxVal) {
cout << "INF\n";
}
else {
cout << cost[i] << "\n";
}
for (auto p : plist[i]) {
cout << p << " ";
}
cout << endl << endl;
}
return 0;
}
//test case
15 55
1 //Starting Node Number
1 2 3
1 4 11
1 5 5
2 1 3
2 3 5
2 5 11
2 6 7
3 2 5
3 6 3
4 1 11
4 5 15
4 7 9
5 1 5
5 2 11
5 6 3
5 7 6
5 8 3
5 9 9
6 2 7
6 3 3
6 5 3
6 9 10
7 4 9
7 5 6
7 8 1
7 10 11
7 11 8
8 5 3
8 7 1
8 9 9
8 11 11
9 5 9
9 6 10
9 8 9
9 11 3
9 12 8
10 7 11
10 13 7
10 14 3
11 7 8
11 8 11
11 9 3
11 12 8
11 14 6
12 9 8
12 11 8
12 15 11
13 10 7
13 15 3
14 10 3
14 11 6
14 15 9
15 12 11
15 13 3
15 14 9
path to 1 costs 0
1
path to 2 costs 3
1 2
path to 3 costs 8
1 2 3
path to 4 costs 11
1 4
path to 5 costs 5
1 5
path to 6 costs 8
1 5 6
path to 7 costs 9
1 5 8 7
path to 8 costs 8
1 5 8
path to 9 costs 14
1 5 9
path to 10 costs 20
1 5 8 7 10
path to 11 costs 17
1 5 8 7 11
path to 12 costs 22
1 5 9 12
path to 13 costs 27
1 5 8 7 10 13
path to 14 costs 23
1 5 8 7 11 14
path to 15 costs 30
1 5 8 7 10 13 15

Generic triangular numbers sequence formula

I know that I can get the nth element of the following sequence
1 3 6 10 15 21
With the formula
(n * (n + 1)) / 2
where n is the nth number I want. How can I generalise the formula to get the nth element of the following sequences where by following sequences I mean
1 -> 1 3 6 10 15 21
2 -> 2 5 9 14 20
3 -> 4 8 13 19
4 -> 7 12 18
5 -> 11 17
6 -> 16
It is not quite clear what do you mean by n-th element in 2D-table (potentially infinite)
Simple formula for element at row and column (numbered from 1):
(r+c-1)*(r+c)/2 - (r-1)
Possible intuition for this formula:
Key moment: element with coordinates r,c stands on the diagonal number d, where d = r + c - 1
There are s = d*(d+1)/2 elements in d filled diagonals, so the last element of d-th diagonal (rightmost top) has value s, and element in r-th row of the same diagonal is
v(r,c) = s-(r-1) = (d)*(d+1)/2 -(r-1) = (r+c-1)*(r+c)/2 - (r-1)

Traffic Light Graph

Say you have a standard graph with values attached to each node and each edge.
You want to go from one node on the graph to another in the shortest amount of time.
The amount of time you have taken so far to traverse this graph will be known as T.
If an edge has value V, traversing that edge will add V to your time spent (T += V).
If a node has a value N, traversing that node will force you to wait until your time spent is divisible by N (T += (N - T % N) % N).
You can think of this like streets and traffic lights.
Driving on a street takes a constant amount of time to reach the other end.
Driving through a traffic light takes the amount of time you have to wait for it to turn green.
For example, lets say you have this graph:
S--6--[1]--2--[7]
| |
3 2
| |
[9]--3--[6]--1--E
Just at a glance, the top path looks faster because it has shorter edges and a shorter delay.
However, the bottom route turns out to be faster. Let's compute the bottom first:
Start: 0 + 6 -> 6
6 % 1 == 0 # We can pass
6 + 3 -> 9
9 % 9 == 0 # We can pass
9 + 3 -> 12
12 % 6 == 0 # We can pass
12 + 1 -> 13
End: 13
And then the top:
Start: 0 + 6 -> 6
6 % 1 == 0 # We can pass
6 + 2 -> 8
8 % 7 != 0 # Have to wait
8 + 6 -> 14
14 % 7 == 0 # We can pass
14 + 2 -> 16
16 % 6 != 0 # Have to wait
16 + 2 -> 18
18 % 6 == 0 # We can pass
18 + 1 -> 19
End: 19
As you can see, the bottom is much shorter.
At small sizes like this it's easier to calculate but at city sizes, you'd need to use some sort of traversal algorithm.
Does anyone know if there's any sort of solution besides brute force?
It is known as shortest path search problem and can be solved by Dijkstra's algorithm in polynomial time. When the lenght of the path is computed, the amount of time spent waiting in the destination vertex should also be added(except for the destination vertex). So it is still the shortest path search problem, but the weight function is slightly different from simple edges' weights sum.

Deletion in red black tree

I am trying to follow the RB-DELETE-FIXUP in Introduction to Algorithm 3rd edition. They have this code:
RB-DELETE-FIXUP(T, x)
1 while x != root[T] and color[x] == BLACK
2 do if x == left[p[x]]
3 then w = right[p[x]]
4 if color[w] == RED
5 then color[w] = BLACK ? Case 1
6 color[p[x]] = RED ? Case 1
7 LEFT-ROTATE(T, p[x]) ? Case 1
8 w = right[p[x]] ? Case 1
9 if color[left[w]] == BLACK and color[right[w]] == BLACK
10 then color[w] = RED ? Case 2
11 x = p[x] ? Case 2
12 else if color[right[w]] == BLACK
13 then color[left[w]] = BLACK ? Case 3
14 color[w] = RED ? Case 3
15 RIGHT-ROTATE(T, w) ? Case 3
16 w = right[p[x]] ? Case 3
17 color[w] = color[p[x]] ? Case 4
18 color[p[x]] = BLACK ? Case 4
19 color[right[w]] = BLACK ? Case 4
20 LEFT-ROTATE(T, p[x]) ? Case 4
21 x = root[T] ? Case 4
22 else (same as then clause with "right" and "left" exchanged)
23 color[x] = BLACK
I am not able to understand how the tree is being balanced in case 4. Looking at this image: (from here)
The result for case 4 is not balanced. From D to A, the black-color height is 2. And D to E, the black-color height is 1. What am I missing here?
What you are missing is that the left hand side is not balanced. This routine is called after the parent of x has been spliced out of the tree, and only if the parent was black. Since the tree was balanced prior to removal of the parent, then we know that the subtree rooted at A must have a black height that it is one less than that of the subtree rooted at D. Since E is originally red and D is black, then the subtree rooted at E must originally have the same black height as A. After the transformation, the color of E is now black, so its black height is now one more than A, so the two sides of the tree are indeed balanced.

Resources