題目
題目連接
php
題目大意是:
給定一張無向有權圖,已知其起點和終點,每一個節點有方向LR或M。蛋糕每次換手須要必定時間x。在方向爲L或R的節點,蛋糕必須在對應的手上,而方向爲M的地方則無所謂。
ios
問最終從起點到終點的最短路程是多少。url
拆點+最短路
這道題,一步一步的來分析spa
第一步,若是沒有對點的方向限制,將會是一個很是簡單的最短路問題。如今有了方向限制。.net
第二步,假設當前僅有左右兩種方向的限制。那麼問題也會變得簡單隻須要將兩端方向不同的邊權加上x,這樣就沒有了方向限制,跑第一步便可。code
第三步,考慮到存在方向爲M的點,能夠將其看做是兩個點,一個是方向爲左的點一個是方向爲右的點,將其拆開,與周圍的點從新建邊。blog
通過這樣一頓操做,圖中就沒有方向爲M的點了,剩下的圖就只剩下方向爲左或者右的點了,按照剛剛第二步分析的那樣實現就好。
圖片
須要注意的是,這裏拆點可能會形成邊的數量不少,建議開10被的m。ci
另外,起點和終點有可能被拆成兩個頂點,爲了避免跑屢次最短路,能夠建造一個虛擬起點和終點分別向拆開的起點和終點鏈接長度爲0的邊。get
代碼:
#include<iostream> #include<algorithm> #include<queue> using namespace std; const int M = 1000060; const int N = 1000060; struct E{ int point; int next; long long dis; }nxt[M]; struct Node{ int po; long long dis; bool operator < (const Node& o)const{ return dis > o.dis; } }; priority_queue<Node> q; int head[N]; int dir[N]; int T,n,m,s1,s2,t1,t2,x,tot,s,t; char dirC[N]; bool vis[N]; void link(int a,int b,long long dis){ nxt[++tot] = {b,head[a],dis}; head[a] = tot; } void dfs1(int k){ vis[k] = true; if(dir[k] == 0){ n++; vis[n] = true; dir[k] = -1; dir[n] = 1; if(k == s1)s2 = n; if(k == t1)t2 = n; for(int i = head[k],j;i;i = nxt[i].next){ j = nxt[i].point; link(j,n,nxt[i].dis); link(n,j,nxt[i].dis); } } for(int i = head[k],j;i;i = nxt[i].next){ if(vis[nxt[i].point]) continue; dfs1(nxt[i].point); } } void dfs2(int k){ vis[k] = true; for(int i = head[k];i;i = nxt[i].next){ nxt[i].dis += (dir[k] != dir[nxt[i].point]) * x; } for(int i = head[k];i;i = nxt[i].next){ if(vis[nxt[i].point]) continue; dfs2(nxt[i].point); } } void clearVis(){ for(int i = 1;i <= n;i++){ vis[i] = false; } } long long dijkstar(){ clearVis(); q.push({s,0}); Node o; while(!q.empty()){ o = q.top(); q.pop(); if(vis[o.po]) continue; if(o.po == t) return o.dis; vis[o.po] = true; for(int i = head[o.po],j;i;i = nxt[i].next){ j = nxt[i].point; if(vis[j]) continue; q.push({j,o.dis + nxt[i].dis}); } } } int main(){ for(cin >> T;T;T--){ tot = 0;s2 = t2 = 0; t = s = 0; while(!q.empty()) q.pop(); scanf("%d%d%d%d%d",&n,&m,&s1,&t1,&x); scanf("%s",dirC + 1); for(int i = 1;i <= n;i++){ if(dirC[i] == 'R') dir[i] = 1; if(dirC[i] == 'L') dir[i] = -1; if(dirC[i] == 'M') dir[i] = 0; } for(int i = 1;i <= n << 1;i++) head[i] = 0; for(int i = 1,a,b,dis;i <= m;i++){ scanf("%d%d%d",&a,&b,&dis); link(a,b,dis); link(b,a,dis); } clearVis(); dfs1(s1); s = ++n;t = ++n; clearVis(); dfs2(s1); if(s2) dfs2(s2); link(s,s1,0); if(s2) link(s,s2,0); link(t1,t,0); if(t2) link(t2,t,0); cout << dijkstar() << endl; } }