问题 D: 最短路径问题
时间限制: 1 Sec 内存限制: 32 MB提交: 41 解决: 13
[提交][状态][讨论版]
题目描述
给你n个点,m条无向边,每条边都有长度d和花费p,给你起点s终点t,要求输出起点到终点的最短距离及其花费,如果最短距离有多条路线,则输出花费最少的。
输入
输入n,m,点的编号是1~n,然后是m行,每行4个数 a,b,d,p,表示a和b之间有一条边,且其长度为d,花费为p。最后一行是两个数 s,t;起点s,终点t。n和m为0时输入结束。
(1<n<=1000, 0<m<100000, s != t)
输出
输出 一行有两个数, 最短距离及其花费。
样例输入
3 2 1 2 5 6 2 3 4 5 1 3 0 0
样例输出
9 11
提示
拿到这题,第一印象就是最短路劲问题(题目写得清清楚楚)。当然,你可以直接套用最短路劲的解法。不过这里我要给大家介绍另一种解法,同样是图论里的算法——深度优先搜索。
从起点开始进行深度优先搜索,当搜索的结点到达终点时查看路径总长度与花费是否比已经得到的最短路径和最小花费小,如果要小的话就使用当前的路径和花费取代最短路径和最小花费。
当遍历到终点时是否就结束了?非也,还需要从其他路径遍历,判断其他路径是否又更短花费更小的。这里就需要用到回溯了。所谓回溯,就是还需要往回走来走其他的路径。那么会不会进入循环状态呢?对遍历过的结点进行标记就能够杜绝循环。当然需要在回溯时取消之前的标记。
提议概括:
有n个顶点,m条无向路,每条路都有距离和花费两个权值,求最短路,若最短路有多条输出花费最小的那条。
解题分析:
这道题只需对dijstra模板的判断条件进行一点的变化就可以了。需要注意的是,对于距离和花费这两个判断条件,他们的地位并不是平等的,而是以距离为第一判断条件,在最短距离相同时才判断花费。这就意味着对于花费也需要建一个像记录距离的dis数组一样去记录花费。同时,这道题也可以像题目提示那里说的一样,可以用深搜来写。下面会给出两种方法的代码。
AC代码:
深搜代码:
1 #include<stdio.h> 2 #include<string.h> 3 4 #define N 1005 5 6 struct node{ 7 int s, w; 8 }e[N][N];//用一个二维结构体数组来记录从一个顶点到另一个顶点的距离和花费 9 10 int maxs, maxw, n, m, t, s; 11 int book[N][N]; 12 13 void dfs(int step, int we, int x) 14 { 15 int i, j, tx, ty; 16 if(x > n)//因为并不是搜索到终点就结束搜索,所以要把这个点所有能跑的点都搜一遍 17 return ; 18 if(x == t){//当到达终点时进行最短距离和最少花费的更新 19 if(step < maxs){//以距离为第一判断条件 20 maxs = step; 21 maxw = we; 22 } 23 else if(step == maxs && we < maxw)//当最短距离相等时再进行花费的判断 24 maxw = we; 25 } 26 for(i = 1; i <= n; i++){ 27 if(book[x][i] == 0){ 29 book[x][i] = -1; 30 dfs(step+e[x][i].s, we+e[x][i].w, i); 31 book[x][i] = 0; 32 } 33 } 34 } 35 36 int main() 37 { 38 int i, j,u , v, w, p; 39 node h; 40 while(scanf("%d%d", &n, &m), n || m){ 41 maxs = maxw = 99999999; 42 memset(book, -1, sizeof(book));//初始化很重要,这里是把所有的点都初始化为不能走任何一个点 43 while(m--){ 44 scanf("%d%d%d%d", &u, &v, &w, &p); 45 e[u][v].s = e[v][u].s = w; 46 e[u][v].w = e[v][u].w = p; 47 book[u][v] = book[v][u] = 0;//当有路是标记为可以走 48 } 49 scanf("%d%d", &s, &t); 50 dfs(0, 0, s); 51 printf("%d %d ", maxs, maxw); 52 } 53 return 0; 54 }
dijstra:
1 #include<stdio.h> 2 #include<string.h> 3 4 #define N 1005 5 #define inf 99999999 6 7 int book[N], e[N][N], dis[N], h[N][N], hh[N]; 8 9 int main() 10 { 11 int i, j, k, n, s, t, u, v, w, sum, f, Min, m, p; 12 while(scanf("%d%d", &n, &m), n || m){ 13 memset(book, 0, sizeof(book)); 14 for(i = 1; i <= n; i++) 15 for(j = 1; j <= n; j++){ 16 if(i == j) e[i][j] = h[i][j] = 0; 17 else e[i][j] = h[i][j] = inf; 18 } 19 20 while(m--){ 21 scanf("%d%d%d%d", &u, &v, &w, &p); 22 if(w < e[u][v]) 23 e[u][v] = e[v][u] = w; 24 if(p < h[u][v]) 25 h[u][v] = h[v][u] = p;//将花费也存入一个地图中 26 } 27 scanf("%d%d", &s, &t); 28 for(i = 1; i <= n; i++){ 29 dis[i] = e[s][i]; 30 hh[i] = h[s][i];//记录起点到i点的最小花费 31 } 32 book[s] = f = 1; 33 while(f < n){ 34 Min = inf; 35 for(i = 1; i <= n; i++) 36 if(!book[i] && dis[i] < Min) 37 Min = dis[i], j = i; 38 book[j] = 1; 39 f++; 40 for(i = 1; i <= n; i++){ 41 if(e[j][i] < inf && dis[i] >= e[j][i] + dis[j]){ 42 if(dis[i] > e[j][i]+dis[j]){//判断条件以距离为第一条件 43 hh[i] = h[j][i]+hh[j]; 44 dis[i] = e[j][i]+dis[j]; 45 } 46 else if(dis[i] == e[j][i]+dis[j] && hh[i] >= h[j][i]+hh[j]) 47 hh[i] = h[j][i]+hh[j]; 48 } 49 } 50 } 51 printf("%d %d ", dis[t], hh[t]); 52 } 53 return 0; 54 }