题目大意:最短路!给定n个点,m条边,可能是无向边,可能是有向边,再给定两点之间的距离,时间,最后给出起点终点,求起点到终点的最短路路径和最快到达路径。
最短路路径:如果最短路不唯一,相同最短路取最快到达的路径。
最快到达路径:如果最快到达路径不唯一,输出经过最少点的路径。
如果路径相同输出 Distance = D; Time = T: source -> u1 -> ... -> destination
如果不相等输出
Distance = D: source -> v1 -> ... -> destination
Time = T: source -> w1 -> ... -> destination
跑两次最短路,但是没必要写两个dijkstra,写一个dijkstra通过传参来判断求的是哪个。
朴素版,和堆优化均可。
#include <iostream>
#include <cstring>
#include <queue>
using namespace std;
typedef pair<int,int> PII;
const int N = 260010;
int e[N],ne[N],w[N],ti[N],h[N],dist[N],fast[N],path[N],idx;
bool st[N];
int n,m,s1,s2;
void add(int a,int b,int c,int d)
{
e[idx] = b,ne[idx] = h[a],w[idx] = c,ti[idx] = d,h[a] = idx ++;
}
string pa,pb;
void dfs(int u,string &p)//取路径
{
if(path[u] == -1)
{
p += to_string(u);return ;
}
dfs(path[u],p);
p = p + " -> " + to_string(u) ;
}
void dijkstra(int w1[],int w2[],int flag)
{
memset(dist,0x3f,sizeof dist);
memset(fast,0x3f,sizeof fast);
memset(st,false,sizeof st);
dist[s1] = 0,fast[s1] = 0;
priority_queue<PII,vector<PII>,greater<PII>> que;
que.push({0,s1});
path[s1] = -1;
while(que.size())
{
auto t = que.top();que.pop();
int u = t.second;
if(st[u]) continue;
if(u == s2) break;
st[u] = true;
for(int i = h[u]; ~i; i = ne[i])
{
int j = e[i];
if(flag) w2[i] = 1;//求最短时间需要用到集合点数
if(!st[j] && dist[j] > dist[u] + w1[i])
{
dist[j] = dist[u] + w1[i];//0.最短路1.最短时间
fast[j] = fast[u] + w2[i];//0.最短时间1.路径最少点
path[j] = u;
que.push({dist[j],j});
}
else if (dist[j] == dist[u] + w1[i] && fast[j] > fast[u] + w2[i])
{
fast[j] = fast[u] + w2[i];
path[j] = u;
}
}
}
}
int main()
{
cin.tie(0);cout.tie(0);
cin >> n >> m;
memset(h,-1,sizeof h);
while(m --)
{
int a,b,c,d,e;
cin >> a >> b >> c >> d >> e;
add(a,b,d,e);
if(!c) add(b,a,d,e);
}
cin >> s1 >> s2;
dijkstra(w,ti,0);int mindist = dist[s2];dfs(s2,pa);
dijkstra(ti,w,1);int mintime = dist[s2];dfs(s2,pb);
if(pa == pb) printf("Distance = %d; Time = %d: %s",mindist,mintime,pa.c_str());
else printf("Distance = %d: %s\nTime = %d: %s",mindist,pa.c_str(),mintime,pb.c_str());
return 0;
}