TT 的旅行日记(Dijkstra)
題意:
眾所周知,TT 有一只魔法貓。
今天他在 B 站上開(kāi)啟了一次旅行直播,記錄他與魔法貓?jiān)谶餍锹糜螘r(shí)的奇遇。 TT 從家里出發(fā),準(zhǔn)備乘坐貓貓快線前往喵星機(jī)場(chǎng)。貓貓快線分為經(jīng)濟(jì)線和商業(yè)線兩種,它們的速度與價(jià)錢都不同。當(dāng)然啦,商業(yè)線要比經(jīng)濟(jì)線貴,TT 平常只能坐經(jīng)濟(jì)線,但是今天 TT 的魔法貓變出了一張商業(yè)線車票,可以坐一站商業(yè)線。假設(shè) TT 換乘的時(shí)間忽略不計(jì),請(qǐng)你幫 TT 找到一條去喵星機(jī)場(chǎng)最快的線路,不然就要誤機(jī)了!
輸入輸出要求:
輸入:輸入包含多組數(shù)據(jù)。每組數(shù)據(jù)第一行為 3 個(gè)整數(shù) N, S 和 E (2 ≤ N ≤ 500, 1 ≤ S, E ≤ 100),即貓貓快線中的車站總數(shù),起點(diǎn)和終點(diǎn)(即喵星機(jī)場(chǎng)所在站)編號(hào)。
下一行包含一個(gè)整數(shù) M (1 ≤ M ≤ 1000),即經(jīng)濟(jì)線的路段條數(shù)。
接下來(lái)有 M 行,每行 3 個(gè)整數(shù) X, Y, Z (1 ≤ X, Y ≤ N, 1 ≤ Z ≤ 100),表示 TT 可以乘坐經(jīng)濟(jì)線在車站 X 和車站 Y 之間往返,其中單程需要 Z 分鐘。
下一行為商業(yè)線的路段條數(shù) K (1 ≤ K ≤ 1000)。
接下來(lái) K 行是商業(yè)線路段的描述,格式同經(jīng)濟(jì)線。
所有路段都是雙向的,但有可能必須使用商業(yè)車票才能到達(dá)機(jī)場(chǎng)。保證最優(yōu)解唯一。
輸出:對(duì)于每組數(shù)據(jù),輸出3行。第一行按訪問(wèn)順序給出 TT 經(jīng)過(guò)的各個(gè)車站(包括起點(diǎn)和終點(diǎn)),第二行是 TT 換乘商業(yè)線的車站編號(hào)(如果沒(méi)有使用商業(yè)線車票,輸出"Ticket Not Used",不含引號(hào)),第三行是 TT 前往喵星機(jī)場(chǎng)花費(fèi)的總時(shí)間。
本題不忽略多余的空格和制表符,且每一組答案間要輸出一個(gè)換行
樣例輸入:
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
思路:
題意分析:
已知起點(diǎn)和終點(diǎn),單源最短路問(wèn)題,且沒(méi)有負(fù)邊,基本可以確定使用Dijkstra算法
Dijkstra:
關(guān)鍵操作:松弛
設(shè)置 s 為源點(diǎn),𝑑𝑖𝑠[a]表示源點(diǎn) s 到點(diǎn) a 的最短距離, 初始化𝑑𝑖𝑠[s]=0,𝑑𝑖𝑠[i]=𝑖𝑛𝑓(無(wú)窮大), 將 s 加入最小堆,每次從堆中取出一個(gè)點(diǎn) x,遍歷 x 的所有鄰接邊 (𝑥,𝑦,𝑤),比較𝑑𝑖𝑠[y] 與𝑑𝑖𝑠[x]+𝑤的大小,若𝑑𝑖𝑠[y]>𝑑𝑖𝑠[x]+𝑤,則松弛成功。更新𝑑𝑖𝑠[y]的大小,將 y 加入最小堆中。不斷執(zhí)行上述操作,直至最小堆為空,最后得到的𝑑𝑖s數(shù)組 即為所求單源最短路值 。
具體分析:
大方向上有兩種情況:使用商業(yè)線,不使用商業(yè)線
其中,使用商業(yè)線又有兩種情況:以起點(diǎn)為源點(diǎn),以終點(diǎn)為源點(diǎn)
依次枚舉每條商業(yè)線(u, v, w),以起點(diǎn)為源點(diǎn)求單源最短路,得到 dis1 數(shù)組,再以終點(diǎn)為源點(diǎn)求單源最短路,得到 dis2 數(shù)組 取 min{dis1[u]+dis2[v]+w, dis1[v]+dis2[u]+w},最終再與不走商業(yè)線的答案dis[E]取min
獲得路徑:這里記錄了每個(gè)節(jié)點(diǎn)的前一個(gè)節(jié)點(diǎn),找到最小路徑之后可以通過(guò)記錄的前一個(gè)節(jié)點(diǎn)依次確定線路。
這里使用鏈?zhǔn)角跋蛐谴鎯?chǔ)邊,注意這是個(gè)無(wú)向圖,在插邊時(shí)要注意一下。
注意點(diǎn):
本題格式上要求比較嚴(yán)格
總結(jié):
1.Dijkstra的模板
2.容易略掉情況:起點(diǎn)為源點(diǎn),終點(diǎn)為源點(diǎn)
3.重復(fù)使用的數(shù)組及時(shí)更新
代碼:
#include<bits/stdc++.h> using namespace std; const int inf=5*1e8;struct edge{int v,w,nxt; }G[2000]; int head[2000],tot; //tot是head的下標(biāo) void init(){tot=0;memset(head,0,sizeof(head)); }void add(int u,int v,int w){G[++tot].v=v; G[tot].w=w; G[tot].nxt=head[u];head[u]=tot; }int dis1[501],dis2[501],pre1[501],pre2[501]; //pre記錄經(jīng)過(guò)節(jié)點(diǎn)的前一個(gè)節(jié)點(diǎn) bool vis[501]; int N,S,E,M,X,Y,Z,K;struct Q{int u,w;bool operator<(const Q &q) const{if(w!=q.w) return w>q.w;} }; void dijkstra1(int s){ //起點(diǎn)S priority_queue<Q> q;for(int i=1;i<=N;i++) {dis1[i]=inf; vis[i]=0; pre1[i]=0;} // memset(vis,0,sizeof(vis)); // memset(pre1,-1,sizeof(pre1));q.push({s,0});dis1[s]=0;pre1[s]=-1;while(!q.empty()){int u=q.top().u;q.pop();if(vis[u]) continue; //已經(jīng)遍歷過(guò)vis[u]=1;for(int i=head[u];i;i=G[i].nxt){int v=G[i].v;if(dis1[v]>dis1[u]+G[i].w){dis1[v]=dis1[u]+G[i].w; //松弛pre1[v]=u; //v前面的節(jié)點(diǎn)是u q.push({v,dis1[v]}); }}} }void dijkstra2(int s){ //終點(diǎn)E priority_queue<Q> q;for(int i=1;i<=N;i++) {dis2[i]=inf; vis[i]=0; pre2[i]=0;} // memset(vis,0,sizeof(vis)); // memset(pre2,-1,sizeof(pre2));q.push({s,0});dis2[s]=0;pre2[s]=-1;while(!q.empty()){int u=q.top().u;q.pop();if(vis[u]) continue; //已經(jīng)遍歷過(guò)vis[u]=1;for(int i=head[u];i;i=G[i].nxt){int v=G[i].v;if(dis2[v]>dis2[u]+G[i].w){dis2[v]=dis2[u]+G[i].w; //松弛pre2[v]=u; //v前面的節(jié)點(diǎn)是u q.push({v,dis2[v]}); }}} } void thePath1(int m){ //從S向前找路徑 if(m==S){printf("%d",m); return;}thePath1(pre1[m]);printf(" %d",m); }void thePath2(int m){ //從E向后找路徑 while(m!=E){printf(" %d",m);m=pre2[m]; }printf(" %d",m); }int main(){int num=1;while(scanf("%d%d%d",&N,&S,&E)!=EOF){int b_start=-1,b_end=-1; //記錄商業(yè)線起點(diǎn)和終點(diǎn) init();scanf("%d",&M);for(int i=0;i<M;i++){scanf("%d%d%d",&X,&Y,&Z);add(X,Y,Z);add(Y,X,Z); //加邊 }dijkstra1(S); dijkstra2(E);int ans=inf; //未使用商業(yè)線 scanf("%d",&K);for(int i=0;i<K;i++){ //枚舉商業(yè)線 scanf("%d%d%d",&X,&Y,&Z);int ans1=dis1[X]+dis2[Y]+Z; //兩種情況取最小值 int ans2=dis2[X]+dis1[Y]+Z;if(ans1<ans) {ans=ans1; b_start=X; b_end=Y;} if(ans2<ans) {ans=ans2; b_start=Y; b_end=X;} }if(num!=1) printf("\n");num++;if(dis1[E]>ans){ //使用了商業(yè)線 thePath1(b_start);thePath2(b_end);printf("\n%d\n",b_start);printf("%d\n",ans);}else{thePath1(E);printf("\nTicket Not Used\n");printf("%d\n",dis1[E]);}}return 0; }總結(jié)
以上是生活随笔為你收集整理的TT 的旅行日记(Dijkstra)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: VOIP流中使用CNN-LSTM下对QI
- 下一篇: 模拟美式橄榄球比赛数据(R)