1. 程式人生 > >P3008 [USACO11JAN]道路和飛機Roads and Planes

P3008 [USACO11JAN]道路和飛機Roads and Planes

tro pen con clu target pty ref www digi

P3008 [USACO11JAN]道路和飛機Roads and Planes

Dijkstra+Tarjan

因為題目有特殊限制所以不用擔心負權的問題

但是樸素的Dijkstra就算用堆優化,也顯然會超時。

這是因為Dj每次擴展時,總是找到費用最小那個點進行擴展。

而本題的毒瘤數據可以在一個圖(設其點數為k)後連一長串負權邊。這樣每次擴展的最壞復雜度O(n^k),T出天際。

但是我們又可以用到題目的特殊限制:一個圖被限制成若幹層,每層的最短路互相無影響

顯然,我們可以用Tarjan縮點法,把圖分層,把每層分離出來,單獨跑一遍Dj。

然後就沒了。(逃

#include<iostream>
#include
<cstdio> #include<cstring> #include<queue> #include<cctype> using namespace std; template <typename T> inline T min(T &a,T &b) {return a<b ?a:b;} template <typename T> inline void read(T &x){ char c=getchar(); x=0; bool f=1; while(!isdigit(c)) f= !f||c==
- ? 0:1,c=getchar(); while(isdigit(c)) x=(x<<3)+(x<<1)+(c^48),c=getchar(); x= f? x:-x; } int n,m1,m2,s,d[25002],cnt1,hd[25002],nxt[150002],ed[25002],poi[150002],val[150002]; int dfs_clock,cnt2,_top,low[25002],dfn[25002],be[25002],st[25002]; //用於Tarjan struct data{ int d,u; bool operator < (const
data &tmp) const { if(be[u]!=be[tmp.u]) return be[u]<be[tmp.u]; //同塊內先處理 return d>tmp.d; } }; priority_queue <data> h; inline void add(int x,int y,int v){ nxt[ed[x]]=++cnt1; hd[x]= hd[x] ? hd[x]:cnt1; ed[x]=cnt1; poi[cnt1]=y; val[cnt1]=v; } inline void tarjan(int x){ //Tarjan模板,可右轉P3387 dfn[x]=low[x]=++dfs_clock; st[++_top]=x; for(int i=hd[x];i;i=nxt[i]){ int to=poi[i]; if(!dfn[to]) tarjan(to),low[x]=min(low[x],low[to]); else if(!be[to]) low[x]=min(low[x],dfn[to]); } if(low[x]==dfn[x]){ //給出每個點所處層的編號 be[x]=++cnt2; while(st[_top]!=x) be[st[_top--]]=cnt2; --_top; } } void dijkstra(){ //裸的 memset(d,127,sizeof(d)); h.push((data){d[s]=0,s}); while(!h.empty()){ data x=h.top(); h.pop(); if(x.d!=d[x.u]) continue; for(int i=hd[x.u];i;i=nxt[i]) if(x.d+val[i]<d[poi[i]]){ d[poi[i]]=x.d+val[i]; h.push((data){d[poi[i]],poi[i]}); } } } int main(){ read(n); read(m1); read(m2); read(s); int q1,q2,q3; for(int i=1;i<=m1;++i) read(q1),read(q2),read(q3),add(q1,q2,q3),add(q2,q1,q3); for(int i=1;i<=m2;++i) read(q1),read(q2),read(q3),add(q1,q2,q3); tarjan(s); //tarjan縮點 for(int i=1;i<=n;++i) if(!dfn[i]) tarjan(i); dijkstra(); for(int i=1;i<=n;++i){ if(d[i]==d[0]) printf("NO PATH\n"); else printf("%d\n",d[i]); }return 0; }

P3008 [USACO11JAN]道路和飛機Roads and Planes