/*最短路径问题 Time Limit : 2000/1000ms (Java/Other) Memory Limit : 32768/32768K (Java/Other) Total Submission(s) : 0 Accepted Submission(s) : 0 Font: Times New Roman | Verdana | Georgia Font Size: ← → Problem Description 给你n个点,m条无向边,每条边都有长度d和花费p,给你起点s终点t,要求输出起点到终点的最短距离及其花费,如果最短距离有多条路线,则输出花费最少的。 Input 输入n,m,点的编号是1~n,然后是m行,每行4个数 a,b,d,p,表示a和b之间有一条边,且其长度为d,花费为p。最后一行是两个数 s,t;起点s,终点。 n和m为0时输入结束。 (1<n<=1000, 0<m<100000, s != t) Output 输出 一行有两个数, 最短距离及其花费。 Sample Input 3 2 1 2 5 6 2 3 4 5 1 3 0 0 Sample Output 9 11 Source 浙大计算机研究生复试上机考试-2010年 */ #include<stdio.h> #include<string.h> #define MAX 1000000000//this can't be 0x7FFFFFFF int map1[1010][1010], map2[1010][1010], start, end, dij1[1010], dij2[1010], n, vis[1010]; void dij(int x, int y)//every time get one min point until the "end" . { int i, j, min1 = MAX, min2 = MAX; for(i = 1; i < n+1; ++i)//get the min point { if(!vis[i] && min1 >= dij1[i])//if the point didn't visit { if(min1 == dij1[i])//when the distance is same { if(min2 > dij2[i])//get the min money { min2 = dij2[i]; j = i;//record the point } } else { min1 = dij1[i]; min2 = dij2[i]; j = i; } } } vis[j] = 1;// the point has been visited if(j == y)//if get the end return ; for(i = 1; i < n+1; ++i)//update { if(!vis[i]) { if(dij1[i] >= dij1[j] + map1[i][j]) { if(dij1[i] == dij1[j] + map1[i][j])//if the distance is same { if(dij2[i] > dij2[j] + map2[i][j])//judge the money { dij2[i] = dij2[j] + map2[i][j]; } } else { dij1[i] = dij1[j] + map1[i][j]; dij2[i] = dij2[j] + map2[i][j]; } } } } dij(x, y); } int main() { int m, i, j; while(scanf("%d%d", &n, &m) != EOF && (n || m)) { int a, b, c, d; for(i = 1; i < n+1; ++i)//initial { for( j = 1; j < n+1; ++j) { map1[i][j] = map1[j][i] = MAX; map2[i][j] = map2[j][i] = MAX; } } for(i = 0; i < m; ++i) { scanf("%d%d%d%d", &a, &b, &c, &d); if(map1[a][b] > c) { map1[a][b] = map1[b][a] = c; map2[a][b] = map2[b][a] = d; } else if(map1[a][b] == c) { if(map2[a][b] > d) map2[a][b] = map2[b][a] = d; } } scanf("%d%d", &start, &end); memset(vis, 0, sizeof(vis)); dij1[start] = 0;//start dij2[start] = 0; vis[start] = 1; for(i = 1; i < n+1; ++i) { if(i != start) { dij1[i] = map1[start][i]; dij2[i] = map2[start][i]; } } dij(start, end); printf("%d %d\n", dij1[end], dij2[end]); } return 0; }
题意:给定n个点,m条无向边,并给出起点和终点,每条边都有个长度和花费值,求起点到终点的最短距离,如果最短距离有重复的,则选择花费最小的那组数据。
思路:由Dij算法给出思路,即以起点为原点,求出每一个点到起点的最短距离以及花费 ,每求出一个点则将这个点标记,并且更新未标记的点到起点的距离,更新方法即判断该点原本的距离和(起点到被标记的点加上被标记的点到该点的距离)谁小,如果遇到更新前后距离相等的,则以花费为标准进行判断,选择最小的作为新的数据,直至遇到终点,则起点到终点的最小距离就出来了。
注意:初始化时,对于输入中未给出的边都默认为无穷大,这里无穷大定义应适当注意范围,在判断时会遇到相加的操作(避免超出int范围)。