1. 程式人生 > >Educational Codeforces Round 38 (Rated for Div. 2) ----D

Educational Codeforces Round 38 (Rated for Div. 2) ----D

pan inf force mes hid get struct include push

D. Buy a Ticket

問題轉換為對於每一個點x,求出一個點y,使得xy的最短路2倍+在y舉辦的費用最小。

考慮建一個超級源點,向每一個點連一條費用為其舉辦所需費用,並且原圖中的邊權值*2,跑一遍最短路,每一個點到超級源點的最短路即為答案。

卡spfa,請用dijkstra。

技術分享圖片
 1 #include<bits/stdc++.h>
 2 #define LL long long
 3 using namespace std;
 4 const int inf=2e5+10;
 5 int n,m;
 6 int tot,fi[inf],to[inf<<2
],nxt[inf<<2]; 7 int s; 8 LL cost[inf<<2]; 9 void link(int x,int y,LL z){ 10 to[++tot]=y;nxt[tot]=fi[x];fi[x]=tot;cost[tot]=z; 11 } 12 LL dis[inf]; 13 struct dijk{ 14 int id; 15 LL val; 16 bool operator < (const dijk &o)const{ 17 return val>o.val;
18 } 19 }; 20 priority_queue<dijk>S; 21 bool vis[inf]; 22 void dijkstra(){ 23 memset(dis,0x3f,sizeof(dis)); 24 dis[s]=0; 25 S.push((dijk){s,0}); 26 while(!S.empty()){ 27 dijk u=S.top(); 28 S.pop(); 29 if(vis[u.id])continue; 30 vis[u.id]=1
; 31 for(int i=fi[u.id];i;i=nxt[i]){ 32 if(dis[to[i]]>dis[u.id]+cost[i]){ 33 dis[to[i]]=dis[u.id]+cost[i]; 34 S.push((dijk){to[i],dis[to[i]]}); 35 } 36 } 37 } 38 } 39 int main() 40 { 41 scanf("%d%d",&n,&m); 42 for(int i=1;i<=m;i++){ 43 int x,y; 44 LL z; 45 scanf("%d%d%lld",&x,&y,&z); 46 link(x,y,z<<1);link(y,x,z<<1); 47 } 48 for(int i=1;i<=n;i++){ 49 LL z; 50 scanf("%lld",&z); 51 link(s,i,z); 52 } 53 dijkstra(); 54 for(int i=1;i<=n;i++)printf("%lld ",dis[i]); 55 puts(""); 56 return 0; 57 }
View Code

真的超級感謝這道題目啊,之前寫的dijkstra一直是不對的,以至於我一直對其復雜度懷疑(事實上確實是不對的),甚至覺得他和不優化的dijkstra不像是一種算法了,普通的dijkstra每一個點只會被拿來更新一次,而我之前寫的優化後的dijkstra是沒有標記數組的,也就是說每一個點可能被訪問多次,復雜度就不是nlog+m了。而且之前從來沒有因為這個被卡過,這次體會到了。

Educational Codeforces Round 38 (Rated for Div. 2) ----D