题意:
众所周知,TT 有一只魔法猫。
今天他在 B 站上开启了一次旅行直播,记录他与魔法猫在喵星旅游时的奇遇。 TT 从家里出发,准备乘坐猫猫快线前往喵星机场。猫猫快线分为经济线和商业线两种,它们的速度与价钱都不同。当然啦,商业线要比经济线贵,TT 平常只能坐经济线,但是今天 TT 的魔法猫变出了一张商业线车票,可以坐一站商业线。假设 TT 换乘的时间忽略不计,请你帮 TT 找到一条去喵星机场最快的线路,不然就要误机了!
输入
输入包含多组数据。
每组数据第一行为 3 个整数 N, S 和 E (2 ≤ N ≤ 500, 1 ≤ S, E ≤ 100),即猫猫快线中的车站总数,起点和终点(即喵星机场所在站)编号。
下一行包含一个整数 M (1 ≤ M ≤ 1000),即经济线的路段条数。
接下来有 M 行,每行 3 个整数 X, Y, Z (1 ≤ X, Y ≤ N, 1 ≤ Z ≤ 100),表示 TT 可以乘坐经济线在车站 X 和车站 Y 之间往返,其中单程需要 Z 分钟。
下一行为商业线的路段条数 K (1 ≤ K ≤ 1000)。
接下来 K 行是商业线路段的描述,格式同经济线。
所有路段都是双向的,但有可能必须使用商业车票才能到达机场。保证最优解唯一。
输出
对于每组数据,输出3行。第一行按访问顺序给出 TT 经过的各个车站(包括起点和终点),第二行是 TT 换乘商业线的车站编号(如果没有使用商业线车票,输出"Ticket Not Used",不含引号),第三行是 TT 前往喵星机场花费的总时间。
本题不忽略多余的空格和制表符,且每一组答案间要输出一个换行
输入样例
4 1 4
4
1 2 2
1 3 3
2 4 4
3 4 5
1
2 4 3
输出样例
1 2 4
25
My Solution:
本题商业线的引入使得问题变得复杂化,如果没有商业线,则问题变成了简单的图问题中的最短路问题。
我们发现加入商业线以后有两种做法,最短路中包含一条商业线或者不包含商业线。
对于不包含商业线的情况,我们可以求一个最短路。
对于包含商业线的情况,因为只走一条商业线,我们可以枚举每一条商业线的情况,然后取最小。
接下来,对于走(一条)商业线的问题怎么求短路呢?
分别从起点和终点跑一次最短路,然后取两次的最小值
min (dis1[u]+dis2[v]+w , dis1[v]+dis2[u]+w )
最后合并以上 以上情况,取最小即可!
1 #include<iostream> 2 #include<string.h> 3 #include<algorithm> 4 using namespace std; 5 const int maxn=1000010; 6 int n,m,k,s,e,tot,ans=10000000,sum; 7 int head[maxn],dis1[maxn],dis2[maxn]; 8 int pre1[maxn],pre2[maxn]; 9 int p[maxn],a[maxn]; 10 bool flag[maxn]; 11 int ans_u,ans_v,ans_w; 12 struct node 13 { 14 int v; 15 int w; 16 int next; 17 }e1[maxn]; 18 void add_edge(int u,int v,int w) 19 { 20 e1[++tot].v=v; 21 e1[tot].w=w; 22 e1[tot].next=head[u]; 23 head[u]=tot; 24 } 25 26 void dijkstra(int u,int *dis,int *pre) 27 { 28 memset(flag,0,sizeof(flag)); 29 for(int i=1;i<=n;i++) 30 dis[i]=maxn; 31 dis[u]=0; 32 for(int i=1;i<=n;i++) 33 { 34 int k=0,minn=maxn; 35 for(int j=1;j<=n;j++) 36 if(!flag[j]&&dis[j]<minn) 37 { 38 minn=dis[j]; 39 k=j; 40 } 41 flag[k]=1; 42 for(int j=head[k];j;j=e1[j].next) 43 if(!flag[e1[j].v]&&dis[e1[j].v]>dis[k]+e1[j].w) //松弛 44 { 45 dis[e1[j].v]=dis[k]+e1[j].w; 46 pre[e1[j].v]=k; 47 } 48 } 49 } 50 int main() 51 { 52 int x,y,z,u,v,w; 53 cin>>n>>s>>e; 54 while(1) 55 { 56 memset(flag,0,sizeof(flag)); 57 memset(pre1,0,sizeof(pre1)); 58 memset(pre2,0,sizeof(pre2)); 59 memset(head,0,sizeof(head)); 60 memset(a,0,sizeof(a)); 61 tot=0; 62 cin>>m; 63 ans_u=0;sum=0; 64 for(int i=1;i<=m;i++) 65 { 66 cin>>x>>y>>z; 67 add_edge(x,y,z); 68 add_edge(y,x,z); 69 } 70 71 dijkstra(s,dis1,pre1) ; 72 dijkstra(e,dis2,pre2) ; 73 74 cin>>k; 75 int ans=dis1[e]; 76 for(int i=1;i<=k;i++) 77 { 78 cin>>u>>v>>w; 79 if(dis1[u]+dis2[v]+w<ans) 80 { 81 ans=dis1[u]+dis2[v]+w; 82 ans_u=u; 83 ans_v=v; 84 } 85 if(dis2[u]+dis1[v]+w<ans)//再次更新 86 { 87 ans=dis2[u]+dis1[v]+w; 88 ans_u=v; 89 ans_v=u; 90 } 91 } 92 int tmp; 93 if(ans_u==0)//不需要商务线 94 { 95 tmp=e; 96 while(tmp) 97 { 98 a[++sum]=tmp; 99 if(tmp==s) break; 100 tmp=pre1[tmp]; 101 } 102 for(int i=sum;i>=2;i--) cout<<a[i]<<" "; 103 cout<<a[1]<<endl; 104 cout<<"Ticket Not Used"<<endl<<ans<<endl; 105 } 106 else//需要商务线 107 { 108 tmp=ans_v; 109 while(tmp) 110 { 111 a[++sum]=tmp; 112 if(tmp==e) break; 113 tmp=pre2[tmp]; 114 } 115 for(int i=1;i<=sum/2;i++) 116 swap(a[i],a[sum-i+1]); 117 tmp=ans_u; 118 while(tmp) 119 { 120 a[++sum]=tmp; 121 if(tmp==s) break; 122 tmp=pre1[tmp]; 123 } 124 for(int i=sum;i>=2;i--) cout<<a[i]<<" "; 125 cout<<a[1]<<endl; 126 cout<<ans_u<<endl<<ans<<endl; 127 } 128 129 if(cin>>n>>s>>e) 130 cout<<endl; //每个输出换行 131 else 132 break; 133 } 134 return 0; 135 }