When the second call is made, the elements in the first part are sorted already, so the second call would be:
The second call would be:
The second call would be:
To perform Dijkstra's algorithm, you maintain a collection of nodes S such that you know the shortest path from s to every node in S. At each step, you add a another node to S, until the ending node is in S. To do this, you also maintain a sorted list of nodes not in S, ordered by their known minimum distance to s. At each step, you put the first node on the list into S, and then process each edge from that node to a node x not in S. If the shortest path to x using this edge is smaller than the currently known shortest path to x, then remove x from the sorted list and re-insert it with the new path.
When you start, you start with S empty. The list will contain all nodes with infinite-length paths, with the exception of node s, whose path length is zero.
Each time an edge is processed in Dijkstra's algorithm, it potentially removes and inserts a node into the sorted list. Thus, its running time is O(E log(V)).
The example is this graph:
The following table shows the steps until D is in S:
S | Sorted List |
{} | { (A,0), (B,inf), (C, inf), (D, inf) } |
{ (A,0) } | { (B,8), (C, 20), (D, inf) } |
{ (A,0), (B,8) } | { (C, 20), (D, 38) } |
{ (A,0), (B,8), (C,20) } | { (D, 26) } |
{ (A,0), (B,8), (C,20), (D,26) } | { } |
Residual Graph |
Flow Graph |
The next path is SDET with a flow of 6. Processing:
Residual Graph |
Flow Graph |
The next path starts with SCF. There are a bunch of these, but the one with the fewest hops goes through that newly created edge (ED) in the residual graph: SCFGEDABT -- flow of 5. As you can see, the residual has separated S from T, so we're done.
Residual Graph |
Flow Graph |
The maximum flow is 8+6+5 = 19. The minimum cut is composed of edges SA, SD and CF. The flow graph is above -- note, I asked for the flow graph and not the residual graph. Grading:
You start with cache[1][l] equal to 1 for l in { 1, 2, 3, 4}, and 0 otherwise. For all other values of d, set cache[d][l] to zero.
Then, you can either calculate cache[d][l] going forward or backward. Forward:
Or backward:
Here are both programs -- first forward (without recursion) in righteous-forward.cpp:
#include <vector> #include <iostream> #include <cstdio> #include <cstdlib> using namespace std; typedef vector <int> IVec; main(int argc, char **argv) { vector <IVec> cache; int n, i, t, l; if (argc != 2) exit(0); n = atoi(argv[1]); if (n < 1) exit(0); cache.resize(n+1); for (i = 1; i <= n; i++) cache[i].resize(10, 0); for (l = 1; l < 5; l++) cache[1][l] = 1; for (i = 2; i < n; i++) { for (l = 0; l+3 < 10; l++) cache[i+1][l+3] += cache[i][l]; for (l = 9; l-2 >= 0; l--) cache[i+1][l-2] += cache[i][l]; } t = 0; for (i = 0; i < 10; i++) t += cache[n][i]; cout << t << endl; } |
And then backward, using recursion and memoization in righteous-backward.cpp:
#include <vector> #include <iostream> #include <cstdio> #include <cstdlib> using namespace std; typedef vector <int> IVec; vector <IVec> cache; int righteous(int d, int l) { int rv; if (cache[d][l] != -1) return cache[d][l]; rv = 0; if (d == 1) { if (l > 0 && l < 5) rv = 1; } else { if (l-3 >= 0) rv += righteous(d-1, l-3); if (l+2 < 10) rv += righteous(d-1, l+2); } cache[d][l] = rv; return rv; } main(int argc, char **argv) { int n, i, t; if (argc != 2) exit(0); n = atoi(argv[1]); if (n < 1) exit(0); cache.resize(n+1); for (i = 1; i <= n; i++) cache[i].resize(10, -1); t = 0; for (i = 0; i < 10; i++) t += righteous(n, i); cout << t << endl; } |
Grading: