最短路径(最基础,经典的模板和思想):HDU-2544最短路
题目:
最短路
Time Limit: 5000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 65437 Accepted Submission(s): 28608
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条商店到赛场的路线。
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
Time Limit: 5000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 65437 Accepted Submission(s): 28608
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条商店到赛场的路线。
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
解题心得:
1、Dijkstra(迪杰斯特拉)算法,主要就是实现这个图的变化过程,注意找过的点要标记。
这个算法的主要思想是从起始点开始,找到离起始点最近点,保留该点到起始点的最小的距离,再从离起始点最小的距离的点再依次找最近点,以起始点为中心,层层扩散,动态图中过程很清晰,主要就是使用代码实现这个动态图。但是要注意标记找过的点。
2、需要注意的一点是,Dijkstra不可以计算带有负边的图。
#include<bits/stdc++.h> using namespace std; const int maxn = 100+10; const int Max = 99999999; int d[1000010]; int maps[maxn][maxn]; int n,m; bool use[maxn];//用于标记,避免循环走 void Ds() { while(1) { int v = -1;//记录最近的点 for(int i=1;i<=n;i++) if((v == -1 || d[i]<d[v]) && !use[i]) v = i; if(v == -1) break; use[v] = 1; for(int i=1;i<=n;i++) d[i] = min(d[i],d[v]+maps[i][v]);//d[v] + maps[i][v],记录从起点到i的距离 } } int main() { //printf("%d",Max); while(scanf("%d%d",&n,&m) && n+m) { for(int i=0;i<maxn;i++) for(int j=0;j<maxn;j++) maps[i][j] = Max;//初始化为最大 memset(use,0,sizeof(use)); for(int i=0;i<=m*n+10;i++) d[i] = Max;//初始化为最大 for(int i=0;i<m;i++) { int start,end; int len; d[1] = 0;//自身走到自身是0,起点初始化为零,如果有多个起点就直接将多个起点全部初始化为0 scanf("%d%d%d",&start,&end,&len); maps[start][end] = maps[end][start] = len;//是双向的并 没有固定方向 } Ds(); printf("%d\n",d[n]); } }
解题心得:
1、Floyd算法其实就是一个动态规划,他的基本思想就是将一个点到另一个点的走法分为两个,第一,从i点走到j点可以直接从i走到j,第二,从i点走到j点可以先从i点走到k点再从k点走到j点,比较这两种走法哪一种更加的优秀就可以了,然后动态规划,从i点到i+1点,一直达到n点。
2、Floyd的时间复杂度是O(n^3),空间复杂度是O(n^2)。
3、很尴尬的是使用了几次这个算法,但是都超时了,时间复杂度是O(n^3),这一点一定要注意,使用之前一定要先计算一下时间的复杂度
#include<bits/stdc++.h> using namespace std; int n,m; const int maxn = 110; const int INF = 0x3f3f3f3f; int maps[maxn][maxn]; void pre_maps() { for(int i=1; i<=n; i++) for(int j=1; j<=n; j++) maps[i][j] = INF; while(m--) { int a,b,len; scanf("%d%d%d",&a,&b,&len); if(len < maps[a][b]) maps[a][b] = maps[b][a] = len; } } void Floyd() { for(int k=1; k<=n; k++) for(int i=1; i<=n; i++) for(int j=1; j<=n; j++) if(maps[i][j] > maps[i][k] + maps[k][j])//在这里k作为中间的转接 maps[i][j] = maps[i][k] + maps[k][j]; } int main() { while(scanf("%d%d",&n,&m) && (n+m)) { pre_maps(); Floyd(); printf("%d\n",maps[1][n]); } return 0; }