#include<cstdio>
#include<cstring>
#include<iostream>
#include<stack>
#include<queue>
#include<vector>
#define inf 0x3f3f3f3f
using namespace std;
const int maxn=1e3+100;
int n,k,q,s,e,m,st,en,co,sizes;
int done[maxn],d1[maxn],d2[maxn],p1[maxn],p2[maxn],cas=0,ans,sss,eee;
struct Node{
int d,u;///d为距离,u顶点
bool operator < (const Node& rhs) const {///重载运算符
return d>rhs.d;
}
};
struct edge{
int st,en,cost;
edge(int ss,int ee,int cc):st(ss),en(ee),cost(cc){}
};
vector<edge> e1;///经济路线
vector<int> G[maxn];///邻接边编号
vector<edge> e2;///商业路线
void init(){
for(int i=0;i<n;i++)
G[i].clear();
e1.clear();
e2.clear();
}
///p数组存放与下标对应点的直接相连的上一条边的编号,不断地e[p[]].st找前一个点,直到与起点相同。
void printE(int type,int temp,int *p){///打印从终点出发的路径
queue<int> c;
c.push(temp);
int tt=p[temp];
edge &eg=e1[tt];
int k=temp;
while(k!=type){
c.push(eg.st);
k=eg.st;
eg=e1[p[k]];
}
if(c.size()>0){
printf(" %d",c.front()+1);
c.pop();
}///注意输出格式,最后一个元素没有空格
while(!c.empty()){
printf(" %d",c.front()+1);
c.pop();
}
}
void printS(int type,int temp,int *p){///打印从S出发的路径
stack<int> c;
c.push(temp);
int tt=p[temp];
edge &eg=e1[tt];
int k=temp;
while(k!=type){
c.push(eg.st);
k=eg.st;
eg=e1[p[k]];
}
if(c.size()>0){
printf("%d",c.top()+1);
c.pop();
}
while(!c.empty()){
printf(" %d",c.top()+1);
c.pop();
}
}
void dj(int s,int *d,int *p){
priority_queue<Node> q;
for(int i=0;i<n;i++)
d[i]=inf;
d[s]=0;
for(int i=0;i<n;i++)
memset(done,0,sizeof(done));
q.push(Node{0,s});
while(!q.empty()){
Node 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 &ed=e1[G[u][i]];
if(d[ed.en]>d[u]+ed.cost){
d[ed.en]=d[u]+ed.cost;
p[ed.en]=G[u][i];
q.push(Node{d[ed.en],ed.en});
}
}
}
}
int main(){
while(scanf("%d%d%d",&n,&s,&e)!=EOF){
if(cas++)
printf("\n");
init();
s--,e--;
sss=eee=-1;
scanf("%d",&m);
for(int i=0;i<m;i++){
scanf("%d%d%d",&st,&en,&co);
e1.push_back(edge(st-1,en-1,co));///双向路线
e1.push_back(edge(en-1,st-1,co));
sizes=e1.size();
G[st-1].push_back(sizes-2);///G中边的序号要对应上e1的下标
G[en-1].push_back(sizes-1);
}
dj(s,d1,p1);///从s出发找到终点的最短路径
dj(e,d2,p2);///从e出发找到起点的最短路径
scanf("%d",&k);
for(int i=0;i<k;i++){
scanf("%d%d%d",&st,&en,&co);
e2.push_back(edge(st-1,en-1,co));
e2.push_back(edge(en-1,st-1,co));
}
ans=d1[e];
for(int i=0;i<e2.size();i++){
int start=e2[i].st;
int fi=e2[i].en;
int time=e2[i].cost;
if(ans>d1[start]+time+d2[fi]){
ans=d1[start]+time+d2[fi];
sss=start;
eee=fi;
}
if(ans>d1[fi]+time+d2[start]){
ans=d1[fi]+time+d2[start];
sss=fi;
eee=start;
}
}
if(eee==-1){
printS(s,e,p1);
printf("\n");
printf("Ticket Not Used\n%d\n",ans);
}
else{
printS(s,sss,p1);
printE(e,eee,p2);
printf("\n");
printf("%d\n",sss+1);
printf("%d\n",ans);
}
}
return 0;
}
这道题开始想到的方法是从起点比较复杂,最后打印路径炒鸡麻烦。不过这也提醒了我头不能太铁,对于计算时间或距离的没有方向的标量,是可以把过程反过来的。像这道题,从起点出发到终点,中间换线的过程,可以看作是从起点到中转站上车点,经过商业线到商业线终点,最后从终点到商业线终点z 这样就可以直接两次迪杰斯特拉,分别是起点到终点,终点到起点,然后再把距离相加就可以。(开始我是多次迪杰斯特拉。。真是笨)
然后就是路径的输出,由于p数组存储的是与下标对应点直接相连的上一条边,所以不断的压栈找到起点,然后输出。如果是从e出发,对应的就是队列。