ACM/ICPC 之 两道dijkstra练习题(ZOJ1053(POJ1122)-ZOJ1053)
两道较为典型的单源最短路径问题,采用dijkstra解法
本来是四道练习题,后来发现后面两道用dijkstra来解的话总觉得有点冗余了,因此暂且分成三篇博客(本篇以及后两篇)。
ZOJ1053(POJ1122)-FDNY to the Rescue!
1 //POJ1122-ZOJ1053 2 //dijkstra-需要记录路径 3 //给出n个路口的邻接矩阵,求给定多个火警到失火点的时间及任一路径 4 //注意输入最后一行时,cin.getline需要两次,猜测需要接受邻接矩阵最后一行其他字符后再接受下一行(有误请指出) 5 //POJ1122:Time:16Ms Memory:208K (单组数据) 6 //ZOJ1053:Time:0Ms Memory:276K (多组数据,中间空一行) 7 #include<iostream> 8 #include<cstring> 9 #include<cstdio> 10 #include<algorithm> 11 using namespace std; 12 13 #define MAX 21 14 #define INF 0x3f3f3f3f 15 16 struct FD { //FDNY 17 int d; //到失火点的距离 18 int num; //FD编号 19 friend bool operator < (FD fd1, FD fd2) { return fd1.d < fd2.d; } 20 }fd[MAX]; 21 22 int n; 23 int road[MAX][MAX]; //有向图-road[i][j]:从i到j的距离 24 int d[MAX]; 25 int fa[MAX]; 26 bool v[MAX]; 27 28 void dijkstra(int x) 29 { 30 memset(v, false, sizeof(v)); 31 v[x] = true; 32 for (int i = 1; i <= n; i++) 33 { 34 d[i] = road[i][x]; 35 fa[i] = x; 36 } 37 for (int i = 1; i <= n; i++) 38 { 39 int mind = INF; 40 int k; 41 for (int j = 1; j <= n; j++) 42 if (!v[j] && mind > d[j]) 43 { 44 mind = d[j]; 45 k = j; 46 } 47 if (mind == INF) return; 48 v[k] = true; 49 for (int j = 1; j <= n; j++) 50 if (!v[j] && d[j] > d[k] + road[j][k]) 51 { 52 d[j] = d[k] + road[j][k]; 53 fa[j] = k; 54 } 55 } 56 } 57 58 int main() 59 { 60 int T; 61 scanf("%d", &T); 62 char str[2*MAX]; 63 cin.getline(str,2*MAX); 64 while (T--) 65 { 66 scanf("%d", &n); 67 for (int i = 1; i <= n; i++) 68 for (int j = 1; j <= n; j++) 69 { 70 scanf("%d", &road[i][j]); 71 if (road[i][j] == -1) road[i][j] = INF; 72 } 73 cin.getline(str, 2 * MAX); 74 cin.getline(str, 2 * MAX); 75 76 dijkstra(str[0] - '0'); 77 printf("Org\tDest\tTime\tPath\n"); 78 int lenfd = 0; 79 int len = strlen(str); 80 for (int i = 2; i < len; i += 2) 81 { 82 fd[lenfd].num = str[i] - '0'; 83 fd[lenfd++].d = d[str[i] - '0']; 84 } 85 86 sort(fd, fd + lenfd); 87 for (int i = 0; i < lenfd; i++) 88 { 89 printf("%d\t%d\t%d\t%d", fd[i].num, str[0] - '0', fd[i].d, fd[i].num); 90 int x = fd[i].num; 91 while (fa[x] != x) 92 printf("\t%d", x = fa[x]); 93 printf("\n"); 94 } 95 if(T) printf("\n"); 96 } 97 return 0; 98 }
ZOJ1053-Transport Goods
1 //dijkstra-松弛变形 2 //题意中的cost请理解为Goods的代价(即消耗Goods的比例),可以比作路上会因各种情况损失货物的比例 3 //博主用的是普通的最短路,不过WA了好几发,初始化-去重-松弛处理都有过问题(做了几个小时啊...) 4 //可以转化为最长路,精度比博主会更好,不过针对此题并无必要 5 //Time:0Ms Memory:360K 6 #include<iostream> 7 #include<cstring> 8 #include<cstdio> 9 using namespace std; 10 11 #define MAX 105 12 #define INF 0x7f7f7f7f 13 14 int n, m; 15 double cost[MAX][MAX]; 16 double d[MAX], w[MAX]; 17 bool v[MAX]; 18 19 void dijkstra() 20 { 21 memset(v, false, sizeof(v)); 22 v[n] = true; 23 for (int i = 1; i < n; i++) 24 d[i] = cost[i][n]; 25 for (int i = 1; i <= n; i++) 26 { 27 double mind = 1; //以1为上界 28 int k; 29 for (int j = 1; j < n; j++) 30 { 31 if (!v[j] && mind > d[j]) 32 { 33 mind = d[j]; 34 k = j; 35 } 36 } 37 if (mind > 1) return; 38 v[k] = true; 39 for (int j = 1; j < n; j++) //松弛 40 if (!v[j] && cost[k][j] < 1 && d[j] > 1 - (1 - d[k]) * (1 - cost[k][j])) 41 d[j] = 1 - (1 - d[k]) * (1 - cost[k][j]); 42 } 43 } 44 45 int main() 46 { 47 //freopen("in.txt", "r", stdin); 48 //freopen("out.txt", "w", stdout); 49 while (scanf("%d%d", &n, &m) != EOF) 50 { 51 memset(cost, INF, sizeof(cost)); 52 memset(w, 0, sizeof(w)); 53 for (int i = 1; i < n; i++) 54 scanf("%lf", &w[i]); 55 for (int j = 0; j < m; j++) 56 { 57 int x, y; 58 double r; 59 scanf("%d%d%lf", &x, &y, &r); 60 if (cost[x][y] > r) //去重 61 cost[y][x] = cost[x][y] = r; 62 } 63 dijkstra(); 64 for (int i = 1; i < n; i++) 65 if (d[i] < 1) 66 w[n] += (1 - d[i]) * w[i]; 67 printf("%.2f\n", w[n]); 68 } 69 return 0; 70 }
他坐在湖边,望向天空,她坐在对岸,盯着湖面