机场快线分为经济线和商业线两种。有一张商业线车票,其他时候只能乘经济线。你的任务是找一条去机场最快的线路。
我们可以枚举商业线的哪一站,假设我们用商业线车票从车站A坐到车站B,则从起点到a,从a到终点这两部分路线对于“经济线网络”来说都应该是最短路。用Dijkstra可以列出两点之间的所有最短路,以及统计最短路的条数。
#include<iostream>
#include<cstring>
#include<queue>
#include<algorithm>
using namespace std;
const int INF=1000000000;
const int maxn=500+10;
struct Edge{
int from,to,dist;
};
struct HeapNode{ //Dijkstra算法用到的优先队列的结点
int d,u;
bool operator < (const HeapNode& rhs)const{
return d>rhs.d;
}
};
struct Dijkstra{
int n,m; //点数和边数
vector<Edge> edges; //边列表
vector<int> G[maxn]; //每个结点出发的边编号(从0开始编号)
bool done[maxn]; //是否已永久标号
int d[maxn]; //s到各个点的距离
int p[maxn]; //最短路中的上一条弧
void init(int n){
this->n=n;
for(int i=0;i<n;i++) G[i].clear();//清空邻接表
edges.clear();
}
void AddEdge(int from,int to,int dist){
//如果是无向图,每条无向边需调用两次AddEdge
Edge edge={from,to,dist};
edges.push_back(edge);
m=edges.size();
G[from].push_back(m-1);
}
void dijkstra(int s){
priority_queue<HeapNode> Q;
for(int i=0;i<n;i++) d[i]=INF;
d[s]=0;
memset(done,0,sizeof(done));
HeapNode heapnode={0,s};
Q.push(heapnode);
while(!Q.empty()){
HeapNode x=Q.top();Q.pop();
int u=x.u;
if(done[u]) continue;
done[u]=true;
for(int i=0;i<G[u].size();i++){
Edge& e=edges[G[u][i]];
if(d[e.to]>d[u]+e.dist){
d[e.to]=d[u]+e.dist;
p[e.to]=G[u][i];
HeapNode heapnode={d[e.to],e.to};
Q.push(heapnode);
}
}
}
}
//dist[i]为s到i的距离,path[i]为s到i的最短路径(经过的结点列表,包括s和t)
void GetShortestPaths(int s,int* dist,vector<int>* paths){
dijkstra(s);
for(int i=0;i<n;i++){
dist[i]=d[i];
paths[i].clear();
int t=i;
paths[i].push_back(t);
while(t!=s){
paths[i].push_back(edges[p[t]].from);
t=edges[p[t]].from;
}
reverse(paths[i].begin(),paths[i].end());
}
}
};
//题目相关
Dijkstra solver;
int d1[maxn],d2[maxn];
vector<int> paths1[maxn],paths2[maxn];
int main(){
int kase=0,N,S,E,M,K,X,Y,Z;
while(cin>>N>>S>>E>>M){
solver.init(N);
S--;E--;//编号从0~N-1
for(int i=0;i<M;i++){
cin>>X>>Y>>Z;X--;Y--;
solver.AddEdge(X,Y,Z);
solver.AddEdge(Y,X,Z);
}
solver.GetShortestPaths(S,d1,paths1);//S到所有点的距离和路径
solver.GetShortestPaths(E,d2,paths2);//T到所有点的距离和路径
int ans=d1[E]; //初始解解为直达距离
vector<int> path=paths1[E]; //初始解的station序列
int midpoint=-1; //不坐商业线
cin>>K;
for(int i = 0; i < K; i++) {
cin>>X>>Y>>Z; X--; Y--;
for(int j = 0; j < 2; j++) { // j=0代表商业线坐X->Y,j=1代表Y->X
if(d1[X] + d2[Y] + Z < ans) {
ans = d1[X] + d2[Y] + Z;
path = paths1[X];
for(int j = paths2[Y].size()-1; j >= 0; j--) // 从Y到T的距离要反过来
path.push_back(paths2[Y][j]);
midpoint = X;
}
swap(X, Y);
}
}
if(kase!=0) cout<<endl;
kase++;
for(int i=0;i<path.size()-1;i++) cout<<path[i]+1<<" ";
cout<<E+1<<endl;
if(midpoint==-1) cout<<"Ticket Not Used"<<endl;
else cout<<midpoint+1<<endl;
cout<<ans<<endl;
}
return 0;
}