Question link: http://acm.hdu.edu.cn/showproblem.php? PID = 1, 2680
An idiot wants to arrive in the shortest time because he wants to take a bus to his friend's house but vomit in the car.
Test data meaning:
Number 3 of the first line: n (number of stations, n <1000) | M (representing the total number of all lines between stations)
| S (representing the station nearest to a friend's house)
There are m rows below: p q t means: a line from P to Q takes t time
There is a number after the M line: w (representing the station that can be taken at the start)
The following W numbers W1, W2.... WW are the station numbers.
Solution report:
From the meaning of the question, we can look at it in turn. Think of it as: from the station s to the station W... whether you are looking at it or looking back at it, it is about finding the shortest path from point to point, and there is no negative weight value (why is there no negative weight value? Let's talk about it below ), it is obvious that Dijkstra is used (if you don't understand it, look at the data structure book p187 ).
Thought: You think, dumb.
If there is a shortest path from I to J (PI ,....... PK, PJ), then (P1 ....... PK) must be a shortest path from I to K. Otherwise, (PI ..... PK, PJ) cannot be the shortest path from I to J. To find the shortest path, Dijkstra proposed an algorithm to generate the shortest path in the ascending order of path length;
What does it mean? The general meaning is: for the original vertex v0, first select the shortest vertex VI in its directly adjacent vertex, then we can know: the shortest distance dis [J] = min (Map [V0] [J], dis [I] + map [I] [J]) is the most important sentence. What does it mean? That is, you can either go directly or go to it again. (I think I am familiar with it. I have seen it when I am planning dynamically or greedy)
Therefore:
Assume that G = <V, E> exists, and the source vertex is v0, u = {v0}. Dis [I] records the shortest distance from V0 to I, map [I] [J] records the distance from I to J
1. Add I to u from vertex I with the smallest dis [I] value in the V-U;
2. Update the DIS value of the vertex directly adjacent to I. (Dist [J] = min {map [V0] [J], DIS [I] + map [I] [J]})
3. Stop until u = v.
# Include <stdio. h> # include <stdlib. h> # include <string. h> # define M 2002 // This place is too bad, Dad. According to the question, I set it to 20002 and didn't execute the function body, return directly # define n 1002 // scope of the data to be viewed # define INF 999999int n, m, s; int map [m] [m]; // map [I] [J] indicates the weight of I to J, int dis [N]; // dis [I] indicates the distance from the origin s to I int visit [N]; // indicates whether the vertex has been accessed by void Dijkstra (INT s) {int I, j, k = 0; int min; memset (visit, 0, sizeof (visit); // for (I = 1; I <= N; I ++) {dis [I] = map [s] [I];} visit [s] = 1; // The first vertex is the origin, and the accessed dis [s] = 0; // s to S is 0 for (I = 1; I <N; I ++) {min = inf; // find the smallest for (j = 1; j <= N; j ++) {If (! Visit [J] & dis [J] <min) {min = dis [J]; k = J; // smallest vertex} If (min = inf) {break;} visit [k] = 1; // The K vertex is accessed // here is the comparison: directly go to or go to // I guess, you dumb will certainly ask: Can't you turn it over? // Answer: it is expanded one by one from the source and has the optimal sub-structure. Each dis [I] retains the shortest distance from S to I. If you break it down after multiple turns, you will know for (j = 1; j <= N; j ++) {If (! Visit [J] & dis [J]> dis [k] + map [k] [J]) {dis [J] = dis [k] + map [k] [J] ;}}return ;}int main () {int I, j; int P, Q, t, W; int Minx, WW; while (scanf ("% d", & N, & M, & S )! = EOF) {memset (DIS, 0, sizeof (DIS); for (I = 1; I <= N; I ++) for (j = 1; j <= N; j ++) {map [I] [J] = inf ;}for (I = 1; I <= m; I ++) {scanf ("% d", & P, & Q, & T); If (T <map [Q] [p]) // If T <= 1000 is specified in the question, Nima will be wrong if it is not added. For future insurance, add map [Q] [p] = T; // note ah, because S (destination) is regarded as the source point, so the direction of the directed graph should be reversed} Dijkstra (s); scanf ("% d", & W); Minx = inf; for (I = 1; I <= W; I ++) // find the smallest dis {scanf ("% d", & ww); If (Minx> dis [WW]) {Minx = dis [WW] ;}} if (minx! = Inf) {printf ("% d \ n", Minx) ;}else {printf ("-1 \ n") ;}} return 0 ;}
Then I explained: Why can't Dijkstra have negative weights ???
For example, if the Edge Map [I] [J] <0 between the adjacent vertex I and j, when the shortest path from V0 to VI is dis [I, so how is dis [J] calculated?
According to our Dijkstra algorithm, this is as obvious as Dist [J] = min {map [V0] [J], DIS [I] + map [I] [J, when dis [I] is calculated, vertex I has been added to the set U of the shortest path, and the shortest path and its length in u will not change, because visit [I]
It has been accessed to 1... The addition of a negative number in DIS [I] is smaller than that in DIS [I], and the calculation of DIS [I] may involve J and I (here I will explain it in detail: According to your understanding, consider all vertices before I and j As A. If the weight from A to I is 10, the weight from A to J is 20, and the weight from I to J is-100, then a must first get dis [I] through I. After that, DIS [I] cannot be changed and then from {A, I} to J. However, we will find that: if the number ranges from A to J and then to I, DIS [I] will be smaller, so an error occurs here. So there is no negative weight ).
What if there is a negative weight?
You can use the Bellman-Ford algorithm.
How to save the path?
Let's just think about it. For example, if you arrive at B in many steps from source point A, and then reach end C in one step, we will think about it.
Dis [B] + cost [B] [C]) = dis [c] This condition indicates that B must be in the path ....
The code is clear ....
# Include <cstdio> # include <iostream> # define Big 5 # include <cstring> # define min (A, B) (a) <(B )? (A) :( B) # define N 6 # define INF 1000005 using namespace STD; int Q [n + 1], DIS [n + 1], vis [n + 1], a, B, CNT; int cost [n + 1] [n + 1] = {0, 0, 0, 0}, {0, 20, 15, INF, INF, INF}, {, 0, INF, INF, 10, 30}, {0, INF, 10}, {0, INF, INF, 0, INF, INF}, {0, INF, 15,0, INF}, {0, INF, 4,10, 0 }}; // int SP [10]; int Index = 0; void dijstra (int u) {memset (VIS, 0, sizeof (VIS); For (INT I = 0; I <= N; I ++) dis [I] = inf; DIS [u] = 0; Vis [u] = 0; For (INT I = 1; I <n; I ++) {int _ min = inf; For (Int J = 1; j <= N; j ++) if (! Vis [J] & dis [J] <_ min) {_ min = dis [J]; u = J;} vis [u] = 1; for (Int J = 1; j <= N; j ++) if (! Vis [J] & dis [J]> dis [u] + cost [u] [J]) dis [J] = dis [u] + cost [u] [J] ;}} void getpath (int u) {q [++ CNT] = u; if (u = A) {for (INT I = CNT; I> 1; I --) {cout <q [I] <"-> "; // SP [index ++] = Q [I];} cout <q [1] <Endl; CNT --; return;} For (INT I = 1; I <= N; I ++) if (I! = U & dis [I] <INF & (DIS [I] + cost [I] [u]) = dis [u]) {getpath (I );} CNT --;} int main () {printf ("input start point and end point: \ n"); While (scanf ("% d", & A, & B )! = EOF) {// SP [1] = A; CNT = 0; if (a = B) {printf ("0 \ n"); continue ;} dijstra (a); If (DIS [B]> = inf) {printf ("No Way To Go ~ \ N "); continue;} getpath (B);} return 0 ;}