题目描述
给你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
提示
拿到这题,第一印象就是最短路劲问题(题目写得清清楚楚)。当然,你可以直接套用最短路劲的解法。不过这里我要给大家介绍另一种解法,同样是图论里的算法——深度优先搜索。
从起点开始进行深度优先搜索,当搜索的结点到达终点时查看路径总长度与花费是否比已经得到的最短路径和最小花费小,如果要小的话就使用当前的路径和花费取代最短路径和最小花费。
当遍历到终点时是否就结束了?非也,还需要从其他路径遍历,判断其他路径是否又更短花费更小的。这里就需要用到回溯了。所谓回溯,就是还需要往回走来走其他的路径。那么会不会进入循环状态呢?对遍历过的结点进行标记就能够杜绝循环。当然需要在回溯时取消之前的标记。
分析:
- 利用Dijkstra算法求得结点s与结点t之间的最短距离,但在更新最短路径的时候需要加入对于路径费用的比较。
- 利用DFS算法遍历从结点s到结点t的路径,并记录最短路径的距离以及花费,若是距离相等就存储花费最小的。
方法一:Dijkstra算法
#include <iostream>
#include <algorithm>
using namespace std;
const int MAXV = 1001;
const int INF = 0x3fffffff;
int n, m, s, t;
int G[MAXV][MAXV], P[MAXV][MAXV], d[MAXV], c[MAXV];
bool vis[MAXV];
void Dijkstra(int s){
fill(d, d + MAXV, INF);
fill(c, c + MAXV, INF);
fill(vis, vis + MAXV, false);
d[s] = c[s] = 0;
for(int i = 0; i < n; i++){
int u = 0, mind = INF;
for(int j = 1; j <= n; j++){
if(vis[j] == false && d[j] < mind){
u = j;
mind = d[j];
}
}
if(u == 0) return;
vis[u] = true;
for(int v = 1; v <= n; v++){
if(vis[v] == false && G[u][v] != INF){
if(d[u] + G[u][v] < d[v]){
d[v] = d[u] + G[u][v];
c[v] = c[u] + P[u][v];
}else if(d[u] + G[u][v] == d[v] && c[u] + P[u][v] < c[v]){
c[v] = c[u] + P[u][v];
}
}
}
}
}
int main()
{
while(cin >> n >> m && (n != 0 && m != 0)){
fill(G[0], G[0] + MAXV * MAXV, INF);
fill(P[0], P[0] + MAXV * MAXV, INF);
for(int i = 0; i < m; i++){
int a, b, d, p;
cin >> a >> b >> d >> p;
G[a][b] = G[b][a] = d;
P[a][b] = P[b][a] = p;
}
cin >> s >> t;
Dijkstra(s);
cout << d[t] << ' ' << c[t] << '\n';
}
return 0;
}
方法二:DFS算法
#include <iostream>
#include <algorithm>
using namespace std;
const int MAXV = 1001;
const int INF = 0x3fffffff;
int n, m, s, t;
int G[MAXV][MAXV], P[MAXV][MAXV];
bool vis[MAXV];
int d, c;
void DFS(int nowv, int nowd, int nowc){
if(nowv == t){
if(nowd < d){
d = nowd;
c = nowc;
}else if(nowd = d && nowc < c){
c = nowc;
}
return;
}
for(int i = 1; i <= n; i++){
if(vis[i] == false && G[nowv][i] != INF){
vis[i] = true;
int tempd = nowd + G[nowv][i];
int tempc = nowc + P[nowv][i];
DFS(i, tempd, tempc);
vis[i] = false;
}
}
}
int main()
{
while(cin >> n >> m && (n != 0 && m != 0)){
fill(G[0], G[0] + MAXV * MAXV, INF);
fill(P[0], P[0] + MAXV * MAXV, INF);
for(int i = 0; i < m; i++){
int a, b, d, p;
cin >> a >> b >> d >> p;
G[a][b] = G[b][a] = d;
P[a][b] = P[b][a] = p;
}
cin >> s >> t;
fill(vis, vis + MAXV, false);
d = c = INF;
DFS(s, 0, 0);
cout << d << ' ' << c << '\n';
}
return 0;
}