Question:
There are N cities, and then the adjacent matrix between these cities is directly given. In the matrix,-1 indicates that the two cities are not connected by road, and other values represent the path length.
If a car passes through a city, you must pay a certain amount of money (possibly a toll ).
Now, from City a to City B, the cost is the sum of the path length, plus the total toll of all cities except the start and end.
Calculate the minimum cost. If multiple channels are matched, the path with the smallest Lexicographic Order is output.
Analysis and Summary:
1. The key to this question is to output the path in Lexicographic Order.
Assume that
1 ---> 2 2
2 ---> 3 1
1 ---> 3 3
Calculate the minimum cost path from 1 to 3.
Obviously, the next two paths are:
1 --> 3 3
1 --> 2 --> 3 3
The cost is the same, but the Lexicographic Order of paths is different. "123" is smaller than "13", so 1 --> 2 --> 3 should be output.
2. Use an array pre to record the previous node of each point. According to the general single-source shortest path algorithm, when there is a single-source shortest path, there is a "less than", and the problem also needs to be judged to be "equal to". When "equal, this is the parent node to be selected if the path Lexicographic Order is small.
Therefore, when "equals", you can find the original path, find the current path, convert the path to a string, and then compare the size to determine whether to change the parent node.
3. The method for finding the path and converting it into a string is actually very simple. It is solved with a three-row recursive function.
4. New things learned in this question:
Then I searched for questions on the Internet and found that I could use the Floyd algorithm to solve the problem. It was amazing that I once again lamented the power of the Floyd algorithm and I only understood it.
Code:
1. SPFA
[Cpp]
# Include <iostream>
# Include <cstdio>
# Include <cstring>
# Include <queue>
Using namespace std;
Const int INF = 0x7fffffff;
Const int VN = 105;
Int n;
Int w [VN] [VN];
Int charge [VN];
Int d [VN];
Int pre [VN];
Bool inq [VN];
Int pos = 0;
Void init (){
For (int I = 0; I <= n; ++ I ){
W [I] [I] = INF;
For (int j = I + 1; j <= n; ++ j)
W [I] [j] = w [j] [I] = INF;
}
}
// Obtain the path from the start point to the current point and convert it to a string
Void dfs (int u, char * str ){
If (u =-1) return;
Dfs (pre [u], str );
Str [pos ++] = u + '0 ';
}
Bool cmp (int origin, int now ){
Char str1 [1, 100], str2 [100];
// 1. Obtain the original path
Pos = 0;
Dfs (origin, str1 );
Str1 [pos] = '\ 0 ';
// 2. Obtain the path of the current vertex
Pos = 0;
Dfs (now, str2 );
Str2 [pos ++] = origin + '0 ';
Str2 [pos] = '\ 0 ';
// 3. Compare whether it is smaller than the original Lexicographic Order
If (strcmp (str1, str2) = 1) return true;
Return false;
}
Void SPFA (int src ){
Memset (inq, 0, sizeof (inq ));
Memset (pre,-1, sizeof (pre ));
Int I, j;
For (I = 1; I <= n; ++ I) d [I] = INF;
D [src] = 0;
Queue <int> q;
Q. push (src );
While (! Q. empty ()){
Int u = q. front (); q. pop ();
Inq [u] = false;
For (int v = 1; v <= n; ++ v) if (w [u] [v]! = INF ){
Int tmp = d [u] + w [u] [v] + charge [v];
If (d [v]> tmp ){
D [v] = tmp;
Pre [v] = u;
If (! Inq [v]) {
Inq [v] = true;
Q. push (v );
}
}
Else if (d [v] = tmp & cmp (v, u )){
Pre [v] = u;
}
}
}
}
// Print the path
Void print_path (int u ){
If (pre [u] =-1 ){
Printf ("% d", u );
Return;
}
Print_path (pre [u]);
Printf ("--> % d", u );
}
Int main (){
Int I, j, src, des;
While (scanf ("% d", & n), n ){
Init ();
For (I = 1; I <= n; ++ I ){
For (j = 1; j <= n; ++ j ){
Scanf ("% d", & w [I] [j]);
If (w [I] [j] =-1) w [I] [j] = INF;
}
}
For (I = 1; I <= n; ++ I)
Scanf ("% d", & charge [I]);
While (scanf ("% d", & src, & des )){
If (src =-1 & des =-1) break;
// Backup
Int tmp1 = charge [src], tmp2 = charge [des];
Charge [src] = 0, charge [des] = 0; // The Tax fee for the start and end points is 0.
SPFA (src );
Printf ("From % d to % d: \ n", src, des );
Printf ("Path :");
Print_path (des );
Printf ("\ nTotal cost: % d \ n", d [des]);
// Restore
Charge [src] = tmp1, charge [des] = tmp2;
}
}
Return 0;
}
2. Floyd record path
[Cpp]
# Include <iostream>
# Include <cstdio>
# Include <cstring>
# Include <queue>
Using namespace std;
Const int INF = 0x7fffffff;
Const int VN = 105;
Int n;
Int w [VN] [VN];
Int path [VN] [VN];
Int charge [VN];
Void init (){
For (int I = 0; I <= n; ++ I ){
For (int j = 0; j <= n; ++ j ){
If (I! = J) w [I] [j] = INF;
Else w [I] [j] = 0;
Path [I] [j] = j; // path [I] [j] indicates the first vertex from vertex I to j'
}
}
}
Void Floyd (){
For (int k = 1; k <= n; ++ k)
For (int I = 1; I <= n; ++ I)
For (int j = 1; j <= n; ++ j) if (w [I] [k]! = INF & w [k] [j]! = INF ){
Int tmp = w [I] [k] + w [k] [j] + charge [k];
If (w [I] [j]> tmp ){
W [I] [j] = tmp;
Path [I] [j] = path [I] [k];
}
Else if (w [I] [j] = tmp & path [I] [j]> path [I] [k]) {
Path [I] [j] = path [I] [k];
}
}
}
Int main (){
Int I, j, src, des;
While (scanf ("% d", & n), n ){
Init ();
For (I = 1; I <= n; ++ I ){
For (j = 1; j <= n; ++ j ){
Scanf ("% d", & w [I] [j]);
If (w [I] [j] =-1) w [I] [j] = INF;
}
}
For (I = 1; I <= n; ++ I)
Scanf ("% d", & charge [I]);
Floyd ();
While (scanf ("% d", & src, & des )){
If (src =-1 & des =-1) break;
Printf ("From % d to % d: \ n", src, des );
Printf ("Path :");
Int u = src;
Printf ("% d", u );
While (u! = Des ){
Printf ("--> % d", path [u] [des]);
U = path [u] [des];
}
Puts ("");
Printf ("Total cost: % d \ n", w [src] [des]);
}
}
Return 0;
}