Input our current position and a destination, an online map can recommend several paths. Now your job is to recommend two paths to your user: one is the shortest, and the other is the fastest. It is guaranteed that a path exists for any request.
Input Specification:
Each input file contains one test case. For each case, the first line gives two positive integers N (2 <= N <= 500), and M, being the total number of streets intersections on a map, and the number of streets, respectively. Then M lines follow, each describes a street in the format:
V1 V2 one-way length time
where V1 and V2 are the indices (from 0 to N-1) of the two ends of the street;one-way is 1 if the street is one-way from V1 toV2, or 0 if not; length is the length of the street; andtime is the time taken to pass the street.
Finally a pair of source and destination is given.
Output Specification:
For each case, first print the shortest path from the source to the destination with distance D in the format:
Distance = D: source -> v1 -> ... -> destination
Then in the next line print the fastest path with total time T:
Time = T: source -> w1 -> ... -> destination
In case the shortest path is not unique, output the fastest one among the shortest paths, which is guaranteed to be unique. In case the fastest path is not unique, output the one that passes through the fewest intersections, which is guaranteed to be unique.
In case the shortest and the fastest paths are identical, print them in one line in the format:
Distance = D; Time = T: source -> u1 -> ... -> destination
Sample Input 1:10 15 0 1 0 1 1 8 0 0 1 1 4 8 1 1 1 3 4 0 3 2 3 9 1 4 1 0 6 0 1 1 7 5 1 2 1 8 5 1 2 1 2 3 0 2 2 2 1 1 1 1 1 3 0 3 1 1 4 0 1 1 9 7 1 3 1 5 1 0 5 2 6 5 1 1 2 3 5Sample Output 1:
Distance = 6: 3 -> 4 -> 8 -> 5 Time = 3: 3 -> 1 -> 5Sample Input 2:
7 9 0 4 1 1 1 1 6 1 1 3 2 6 1 1 1 2 5 1 2 2 3 0 0 1 1 3 1 1 1 3 3 2 1 1 2 4 5 0 2 2 6 5 1 1 2 3 5Sample Output 2:
Distance = 3; Time = 4: 3 -> 2 -> 5
题目大意
有一张<N,M>的图(N个节点0-N-1,M条路),每条路的格式为<V1,V2,one-way,length,time>其中v1,v2分别为两个端点,one-way=0表示此边为无向边,one-way=1表示此边是有向边,length为这条路的距离,time为这条路上花费的时间。最后给出起点S、终点T。
求:S到T的最短距离及路径:如果有多条最短距离的路径,输出花费时间最少的那条(test数据保证唯一)。
S到T的最短时间及路径:如果有多条最短时间的路径,输出经过结点最少的一条(test数据保证唯一)。
解题思路
pat里的图几乎所有的用矩阵保存都能做,写起来也简单(链式前向星或STL保存会比较快)。而且这道题不考虑重边和自环都能过。
求最短距离时:只要把dijk算法中更新最短距离中,距离相同时(dist[]=dist[]+mp[][][0]),选择时间更少的(tim[]>tim[]+mp[][][0])即可。
求最短时间时:只要把dijk算法中更新最短时间中,时间相同时(dist[]=dist[]+mp[][][1]),选择节点更少的(leng[]>leng[]+1)即可。
这两部分也可以合并成一个dijk写,为了方便阅读代码,我把球最短距离和最短时间的代码分成了dijk1(), dijk2()。
坑点:没有坑点,变形的最短路问题。
#include <cstdio>
#include <vector>
#include <map>
#include <set>
#include <queue>
#include <stack>
#include <cstdlib>
#include <climits>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
#define ll long long
const int MAXN = 500 + 5;
const int MAXM = 100000 + 5;
const int INF = 0x7f7f7f7f;
template <class XSD> inline XSD f_min(XSD a, XSD b) { if (a > b) a = b; return a; }
template <class XSD> inline XSD f_max(XSD a, XSD b) { if (a < b) a = b; return a; }
int n, m;
int s, t;
int mp[MAXN][MAXN][2];///mp[][][0]距离 mp[][][1]时间
void Getdata(){
memset(mp, 0x7f, sizeof mp);
int u, v, op, le, ti;
for(int i=0; i<m; i++){
scanf("%d%d%d%d%d", &u, &v, &op, &le, &ti);
if(op) mp[u][v][0]=le, mp[u][v][1]=ti;
else mp[u][v][0]=mp[v][u][0]=le, mp[u][v][1]=mp[v][u][1]=ti;
}
scanf("%d%d", &s, &t);
}
int dist[MAXN], tim[MAXN];
int pre[MAXN];///路径前驱节点
bool vis[MAXN];
int dijk1(){///最短距离
memset(vis, false, sizeof vis);
for(int i=0; i<n; i++) dist[i] = mp[s][i][0], tim[i]=mp[s][i][1], pre[i]=s;
int T=n;
vis[s]=true, dist[s]=0, tim[s]=0;
while(T--){
int min_=INF, pos=s;
for(int i=0; i<n; i++){
if(!vis[i] && dist[i]<min_){
pos=i;
min_=dist[i];
}
}
vis[pos]=true;
for(int i=0; i<n; i++){
if(mp[pos][i][0]!=INF && !vis[i]){
if(dist[pos]+mp[pos][i][0]<dist[i]){
dist[i]=dist[pos]+mp[pos][i][0];
tim[i]=tim[pos]+mp[pos][i][1];
pre[i]=pos;
}
else if(dist[i]==dist[pos]+mp[pos][i][0] && tim[i]>tim[pos]+mp[pos][i][1]){///距离相同选时间最少的
tim[i]=tim[pos]+mp[pos][i][1];
pre[i]=pos;
}
}
}
}
return dist[t];
}
int leng[MAXN];///节点距离
int dijk2(){///最短时间
memset(vis, false, sizeof vis);
for(int i=0; i<n; i++) dist[i] = mp[s][i][1], pre[i]=s;
int T=n;
vis[s]=true, dist[s]=0, leng[s]=0;
while(T--){
int min_=INF, pos=s;
for(int i=0; i<n; i++){
if(!vis[i] && dist[i]<min_){
pos=i;
min_=dist[i];
}
}
vis[pos]=true;
for(int i=0; i<n; i++){
if(mp[pos][i][1]!=INF && !vis[i]){
if(dist[pos]+mp[pos][i][1]<dist[i]){
dist[i]=dist[pos]+mp[pos][i][1];
leng[i]=leng[pos]+1;
pre[i]=pos;
}
else if(dist[i]==dist[pos]+mp[pos][i][1] && leng[i]>leng[pos]+1){///距离相同选时间最少的
leng[i]=leng[pos]+1;
pre[i]=pos;
}
}
}
}
return dist[t];
}
int ans1[MAXN], ans1_, ans2[MAXN], ans2_; ///结果输出统计
void Solve(){
int ct1=0, ct2=0;///最短距离、最短时间路径计数
stack<int>s0;
///最短距离
s0.push(t);
ans1_ = dijk1();
int u=s, v=t;
while(u!=v){s0.push(pre[v]);v=pre[v];}
while(!s0.empty()){ans1[ct1++]=s0.top();s0.pop();}
///最短时间
s0.push(t);
ans2_ = dijk2();
u=s, v=t;
while(u!=v){s0.push(pre[v]);v=pre[v];}
while(!s0.empty()){ans2[ct2++]=s0.top();s0.pop();}
///输出
bool same=true;
if(ct1!=ct2) same=false;
else{///判断路径是否相同
for(int i=0; i<ct1; i++)
if(ans1[i]!=ans2[i]) {same=false;break;}
}
if(same){
printf("Distance = %d; Time = %d: ", ans1_, ans2_);
for(int i=0; i<ct1; i++) printf("%d%s", ans1[i], i!=(ct1-1)?" -> ":"\n");
}
else{
printf("Distance = %d: ", ans1_);
for(int i=0; i<ct1; i++) printf("%d%s", ans1[i], i!=(ct1-1)?" -> ":"\n");
printf("Time = %d: ", ans2_);
for(int i=0; i<ct2; i++) printf("%d%s", ans2[i], i!=(ct2-1)?" -> ":"\n");
}
}
int main(){
while(~scanf("%d%d", &n, &m)){
Getdata();
Solve();
}
return 0;
}