拓撲排序/DP【洛谷P2883】 [USACO07MAR]牛交通Cow Traffic
阿新 • • 發佈:2018-10-18
起點 排序。 add wap 瓶頸 push out 農場 using
P2883 [USACO07MAR]牛交通Cow Traffic
隨著牛的數量增加,農場的道路的擁擠現象十分嚴重,特別是在每天晚上的擠奶時間。為了解決這個問題,FJ決定研究這個問題,以能找到導致擁堵現象的瓶頸所在。
牧場共有M條單向道路,每條道路連接著兩個不同的交叉路口,為了方便研究,FJ將這些交叉路口編號為1..N,而牛圈位於交叉路口N。任意一條單向道路的方向一定是是從編號低的路口到編號高的路口,因此農場中不會有環型路徑。同時,可能存在某兩個交叉路口不止一條單向道路徑連接的情況。
在擠奶時間到來的時候,奶牛們開始從各自的放牧地點回到牛圈。放牧地點是指那些沒有道路連接進來的路口(入度為0的頂點)。
現在請你幫助fj通過計算從放牧點到達牛圈的路徑數目來找到最繁忙的道路(答案保證是不超過32位整數)。
思維固化了。
看到這題直接套上P1685 遊覽的板子。
才得60分。
再讀題(看題解),發現這題會有多個起點,多個終點。
那麽對於多個終點,只能去n,所以還要從n建反邊跑一邊拓撲排序,這樣一條邊的貢獻就是\(g(u)*f(v)\)。
好像我用了最笨的方法跑兩邊拓撲排序。
code:
#include <iostream> #include <cstdio> #include <queue> using namespace std; const int wx=500017; inline int read(){ int sum=0,f=1; char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-')f=-1; ch=getchar();} while(ch>='0'&&ch<='9'){sum=(sum<<1)+(sum<<3)+ch-'0'; ch=getchar();} return sum*f; } int n,m,ans; int num,tot; int g[wx],head[wx],h[wx],f[wx]; int in[wx],out[wx],in2[wx],out2[wx]; struct e{ int nxt,to; }edge[wx*2]; void add(int from,int to){ edge[++num].nxt=head[from]; edge[num].to=to; head[from]=num; } struct ee{ int nxt,to; }e[wx*2]; void ADD(int from,int to){ e[++tot].nxt=h[from]; e[tot].to=to; h[from]=tot; } queue<int > q; void bfs1(){ for(int i=1;i<=n;i++)if(!in[i])g[i]=1,q.push(i); while(q.size()){ int u=q.front(); q.pop(); for(int i=head[u];i;i=edge[i].nxt){ int v=edge[i].to; g[v]+=g[u]; in[v]--; if(!in[v]){ q.push(v); } } } } void bfs2(){ for(int i=1;i<=n;i++)if(!in2[i])f[i]=1,q.push(i); while(q.size()){ int u=q.front(); q.pop(); for(int i=h[u];i;i=e[i].nxt){ int v=e[i].to; f[v]+=f[u]; in2[v]--; if(!in2[v])q.push(v); } } for(int u=1;u<=n;u++){ for(int i=head[u];i;i=edge[i].nxt){ int v=edge[i].to; ans=max(ans,g[u]*f[v]); } } } int main(){ n=read(); m=read(); for(int i=1;i<=m;i++){ int x,y; x=read(); y=read(); if(x>y)swap(x,y); add(x,y); in[y]++; out[x]++; ADD(y,x); in2[x]++; out2[y]++; } bfs1(); bfs2(); printf("%d\n",ans); return 0; }
拓撲排序/DP【洛谷P2883】 [USACO07MAR]牛交通Cow Traffic