题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2544
最短路
Time Limit: 5000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 67093 Accepted Submission(s): 29309
Problem Description
在每年的校赛里,所有进入决赛的同学都会获得一件很漂亮的t-shirt。但是每当我们的工作人员把上百件的衣服从商店运回到赛场的时候,却是非常累的!所以现在他们想要寻找最短的从商店到赛场的路线,你可以帮助他们吗?
Input
输入包括多组数据。每组数据第一行是两个整数N、M(N<=100,M<=10000),N表示成都的大街上有几个路口,标号为1的路口是商店所在地,标号为N的路口是赛场所在地,M则表示在成都有几条路。N=M=0表示输入结束。接下来M行,每行包括3个整数A,B,C(1<=A,B<=N,1<=C<=1000),表示在路口A与路口B之间有一条路,我们的工作人员需要C分钟的时间走过这条路。
输入保证至少存在1条商店到赛场的路线。
输入保证至少存在1条商店到赛场的路线。
Output
对于每组输入,输出一行,表示工作人员从商店走到赛场的最短时间
Sample Input
2 1 1 2 3 3 3 1 2 5 2 3 5 3 1 2 0 0
Sample Output
3 2//3种最短路算法, 直接套模板 //由于数据比较水,所以Floyd算法也能过 #include <stdio.h> #include <queue> #include <stack> #include <string.h> #include <algorithm> #define maxn 1005 #define inf 0x3f3f3f3f using namespace std; int dist[maxn]; //记录源点到各个点的最短路径长度 int edge[maxn][maxn];//邻接矩阵存边 int pre[maxn]; //记录一个路径中,到达某个点的前一个点 bool vis[maxn]; //记录某个元素是否在队列内 int cnt[maxn]; //记录一个元素入队的次数,如果大于nodenum-1,那么就存在负权回路 int Fdist[maxn][maxn]; //记录Floyd算法的任意两点的最短距离 int Fpre[maxn][maxn]; //记录一个路径中两点之间的中间点 queue<int>q; //SPFA算法中用到的队列 void Floyd(int orig, int nodenum) { for(int i=1; i<=nodenum; i++) for(int j=1; j<=nodenum; j++) { Fdist[i][j] = edge[i][j]; Fpre[i][j] = -1; } for(int k=1; k<=nodenum; k++) for(int i=1; i<=nodenum; i++) { if(Fdist[i][k]!=inf) { for(int j=1; j<=nodenum; j++) { if(Fdist[i][j] > Fdist[i][k]+Fdist[k][j]) { Fdist[i][j] = Fdist[i][k]+Fdist[k][j]; Fpre[i][j] = k; } } } } } void Dijkstra(int orig, int nodenum) { memset(vis, 0, sizeof(vis)); memset(pre, -1, sizeof(pre)); for(int i=1; i<=nodenum; i++) { dist[i] = edge[orig][i]; if(dist[i]!=inf) pre[i] = orig; } vis[orig] = 1; for(int i=1; i<nodenum; i++) { int u = orig, cntmin = inf; for(int j=1; j<=nodenum; j++) { if(!vis[j]&&dist[j]<cntmin) { u = j; cntmin = dist[j]; } } vis[u] = 1; for(int j=1; j<=nodenum; j++) { if(!vis[j] && dist[j] > dist[u]+edge[u][j]) { dist[j] = dist[u]+edge[u][j]; pre[j] = u; } } } } bool SPFA(int orig, int nodenum) { while(!q.empty()) q.pop(); memset(vis, false, sizeof(vis)); memset(pre, -1, sizeof(pre)); memset(cnt, 0, sizeof(cnt)); for(int i=1; i<=nodenum; i++) dist[i] = inf; vis[orig] = true; pre[orig] = orig; cnt[orig]++; dist[orig] = 0; q.push(orig); while(!q.empty()) { int u = q.front(); q.pop(); vis[u] = false; for(int v=1; v<=nodenum; v++) { if(dist[v] > dist[u]+edge[u][v]) { dist[v] = dist[u]+edge[u][v]; pre[v] = u; if(!vis[v]) { vis[v] = true; cnt[v]++; q.push(v); if(cnt[v]>nodenum-1) return false; } } } } return true; } //Floyd算法,点s到t的路径 void Floyd_path(int s, int t) { if(Fdist[s][t]==inf) { printf("%d---%d--no load\n", s, t); return; } if(Fpre[s][t]==-1) return; int k = Fpre[s][t]; Floyd_path(s, k); printf("%d->", k); Floyd_path(k, t); } //Dijkstra和SPFA算法,最短路的路径 void p_path(int orig, int node) { stack<int>path; while(node!=pre[node]) { path.push(node); node = pre[node]; } printf("%d->", node); while(!path.empty()) { printf("%d->", path.top()); path.pop(); } printf("\n\n"); } void DisPath(int orig, int nodenum) { for(int i=1; i<=nodenum; i++) { if(dist[i]!=inf) { printf("%d到%d的最短路径长度是:%d\n", orig, i, dist[i]); printf("路径是:"); p_path(orig, i); } else { printf("%d到%d没有路径\n\n", orig, i); } } } int main() { int nodenum, edgenum, orig; //结点数,边数,源点 while(scanf("%d%d", &nodenum, &edgenum), nodenum+edgenum) { orig = 1; for(int i=0; i<=nodenum; i++) for(int j=1; j<=nodenum; j++) edge[i][j] = i==j?0:inf; for(int i=1; i<=edgenum; i++) { int u, v, cost; scanf("%d%d%d", &u, &v, &cost); edge[v][u] = edge[u][v] = min(edge[u][v], cost); } //SPFA(orig, nodenum); Dijkstra(orig, nodenum); //Floyd(orig, nodenum); //printf("%d\n", Fdist[1][nodenum]); printf("%d\n", dist[nodenum]); } return 0; }
还有Bellman算法,但是提交后,一直runtime error,下面是代码(该代码未ac)//Bellman算法 #include <stdio.h> #include <string.h> #include <algorithm> #include <stack> #include <map> #define maxn 1005 #define inf 0x3f3f3f3f using namespace std; map<int, int>mp; struct Edge { int u, v; }edge[maxn<<1]; int dist[maxn]; int pre[maxn]; void p_path(int orig, int node) { stack<int>path; while(node!=pre[node]) { path.push(node); node = pre[node]; } printf("%d->", node); while(!path.empty()) { printf("%d->", path.top()); path.pop(); } printf("\n\n"); } void DisPath(int orig, int nodenum) { for(int i=1; i<=nodenum; i++) { if(dist[i]!=inf) { printf("%d到%d的最短路径长度是:%d\n", orig, i, dist[i]); printf("路径是:"); p_path(orig, i); } else { printf("%d到%d没有路径\n\n", orig, i); } } } bool Bellman(int orig,int nodenum, int edgenum) { for(int i=1; i<=nodenum; i++) { dist[i] = inf; pre[i] = -1; } dist[orig] = 0; pre[orig] = orig; for(int i=1; i<nodenum; i++) { for(int j=0; j<edgenum; j++) { if(dist[edge[j].v] > dist[edge[j].u] + mp[edge[j].u*maxn + edge[j].v]) { pre[edge[j].v] = edge[j].u; dist[edge[j].v] = dist[edge[j].u] + mp[edge[j].u*maxn + edge[j].v]; } } } bool res = true; for(int j=0; j<edgenum; j++) { if(dist[edge[j].v] > dist[edge[j].u] + mp[edge[j].u*maxn + edge[j].v]) { res = false; break; } } return res; } int main() { int u[maxn], v[maxn], cost[maxn]; int nodenum, edgenum, orig; while(scanf("%d%d", &nodenum, &edgenum), nodenum+edgenum) { orig = 1; int e = 0; mp.clear(); for(int i=1; i<=edgenum; i++) { scanf("%d%d%d", &u[i], &v[i], &cost[i]); } //因为图是无向图,且可重边,所以用map[u*maxn + v]表示点u与点v的边的权值 for(int i=1; i<=edgenum; i++) { if(mp[u[i]*maxn+v[i]]>0) { mp[v[i]*maxn+u[i]] = mp[u[i]*maxn+v[i]] = min(mp[u[i]*maxn+v[i]], cost[i]); } else { edge[e++].u = u[i]; edge[e-1].v = v[i]; edge[e++].u = v[i]; edge[e-1].v = u[i]; mp[v[i]*maxn+u[i]] = mp[u[i]*maxn+v[i]] = cost[i]; } } if(Bellman(orig, nodenum, e)) { printf("%d\n", dist[nodenum]); // DisPath(orig, nodenum); } else printf("存在负权回路\n"); } return 0; }