TT 的旅行日记
題目:TT 的旅行日記
題意:眾所周知,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
2
5
解題思路:首先如果沒有那個商業線,就是一個單純的最短源路徑問題;有了商業線,就變得復雜了起來;這里使用的方法是:
雙層圖結構,上下點相同,中間多了條路徑;我可以先以起點為原點跑一遍最短路,再以終點為原點跑一遍最短路;然后枚舉所有的商業線x,y,z;從起點到x或y,從終點到y或x,之后加個z和原來的從起點到終點比較一下就行了;
代碼:
#include<iostream> #include<cstdio> #include<cstdlib> #include<cstring> #include<vector> #include<queue> #define Max 1000000000 using namespace std; struct node {int to;int next;int v; }e[20005]; int n,a,b,m,k,ticket=-1; int d1[20005],color1[20005],p1[20005]={0}; int d2[20005],color2[20005],p2[20005]={0}; int head[2005],tot=0; int flag=0; void add(int x,int y,int z) {e[++tot].to=y;e[tot].next=head[x];e[tot].v=z;head[x]=tot; } void dij1()//堆優化+前向星的dij {for(int i=1;i<=n;i++){d1[i]=Max;}d1[a]=0;pair<int,int> s=make_pair(0,a);priority_queue<pair<int,int> ,vector<pair<int,int> >,greater<pair<int,int> > > q;q.push(s);int t;while(!q.empty()){pair<int,int> u=q.top();q.pop();int u1=u.first,u2=u.second;color1[u2]=1;for(int i=head[u2];i;i=e[i].next){int j=e[i].to,w=e[i].v;if(color1[j]!=1){if(d1[j]>d1[u2]+w){d1[j]=d1[u2]+w;q.push(make_pair(d1[j],j));p1[j]=u2;}}}} } void dij2() {for(int i=1;i<=n;i++){d2[i]=Max;}d2[b]=0;pair<int,int> s=make_pair(0,b);priority_queue<pair<int,int> ,vector<pair<int,int> >,greater<pair<int,int> > > q;q.push(s);int t;while(!q.empty()){pair<int,int> u=q.top();q.pop();int u1=u.first,u2=u.second;color2[u2]=1;for(int i=head[u2];i;i=e[i].next){int j=e[i].to,w=e[i].v;if(color2[j]!=1){if(d2[j]>d2[u2]+w){d2[j]=d2[u2]+w;q.push(make_pair(d2[j],j));p2[j]=u2;}}}} } int main() {while(scanf("%d%d%d",&n,&a,&b)!=EOF){if(!flag) flag=true;//這個是格式問題,每組答案有個空行,最后不能有空行else printf("\n");tot=0;memset(head,0,sizeof(head));memset(color1,0,sizeof(color1));memset(color2,0,sizeof(color2));memset(p1,0,sizeof(p1));memset(p2,0,sizeof(p2));scanf("%d",&m);int x,y,z;for(int i=0;i<m;i++){scanf("%d%d%d",&x,&y,&z);add(x,y,z);add(y,x,z);}dij1();//跑兩遍dijdij2();int ans=d1[b];scanf("%d",&k);int t1,t2;for(int i=0;i<k;i++){scanf("%d%d%d",&x,&y,&z);if(d1[x]+d2[y]<d1[y]+d2[x]){if(d1[x]+d2[y]+z<ans){ticket=x;ans=d1[x]+d2[y]+z;t1=x,t2=y;}}else{if(d1[y]+d2[x]+z<ans){ticket=y;ans=d1[y]+d2[x]+z;t1=y,t2=x;}}}vector<int> v;//這是我用的路徑記錄,記錄的是兒子節點if(ans==d1[b]){int tt=b;while(tt!=a){v.push_back(tt);tt=p1[tt];}v.push_back(a);for(int i=v.size()-1;i>=0;i--){if(i+1-v.size()){printf(" ");}printf("%d",v[i]);}}else{int tt=t1;while(tt!=a){v.push_back(tt);tt=p1[tt];}v.push_back(a);tt=t2;while(tt!=b){v.insert(v.begin(),tt);tt=p2[tt];}v.insert(v.begin(),b);for(int i=v.size()-1;i>=0;i--){if(i+1-v.size()){printf(" ");}printf("%d",v[i]);}}if(ans==d1[b])//特判一下{printf("\nTicket Not Used\n%d\n",ans);}elseprintf("\n%d\n%d\n",ticket,ans);} }總結
- 上一篇: ubuntu搭建NAS服务器——序
- 下一篇: System类详解