bzoj1638 / P2883 [USACO07MAR]牛交通Cow Traffic
P2883 [USACO07MAR]牛交通Cow Traffic
对于每一条边$(u,v)$
设入度为0的点到$u$有$f[u]$种走法
点$n$到$v$(通过反向边)有$f2[v]$种走法
显然经过这条边的方案数为$f[u]*f2[v]$
两边递推处理$f$数组,然后枚举每条边取个$max$。
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<queue> 5 using namespace std; 6 void swap(int &a,int &b){a^=b^=a^=b;} 7 int max(int &a,int &b){return a>b?a:b;} 8 #define N 5005 9 #define M 50002 10 int n,m,f[N],f2[N],in[N],in2[N],ans; 11 int cnt,hd[N],nxt[M],ed[N],poi[M]; 12 int cnt2,hd2[N],nxt2[M],ed2[N],poi2[M]; 13 queue <int> h; 14 void adde(int x,int y){ 15 nxt[ed[x]]=++cnt; hd[x]=hd[x]?hd[x]:cnt; 16 ed[x]=cnt; poi[cnt]=y; ++in[y]; 17 } 18 void adde2(int x,int y){ 19 nxt2[ed2[x]]=++cnt2; hd2[x]=hd2[x]?hd2[x]:cnt2; 20 ed2[x]=cnt2; poi2[cnt2]=y; ++in2[y]; 21 } 22 int main(){ 23 scanf("%d%d",&n,&m); 24 for(int i=1,q1,q2;i<=m;++i){ 25 scanf("%d%d",&q1,&q2); 26 if(q1>q2) swap(q1,q2); 27 adde(q1,q2); adde2(q2,q1); 28 } 29 for(int i=1;i<=n;++i) if(!in[i]) h.push(i),f[i]=1; 30 while(!h.empty()){ 31 int x=h.front(); h.pop(); 32 for(int i=hd[x];i;i=nxt[i]){ 33 int to=poi[i]; 34 f[to]+=f[x]; --in[to]; 35 if(in[to]==0) h.push(to); 36 } 37 }//以上正向图,以下反向图 38 h.push(n),f2[n]=1; 39 while(!h.empty()){ 40 int x=h.front(); h.pop(); 41 for(int i=hd2[x];i;i=nxt2[i]){ 42 int to=poi2[i]; 43 f2[to]+=f2[x]; --in2[to]; 44 if(in2[to]==0) h.push(to); 45 } 46 } 47 for(int i=1;i<=n;++i) 48 for(int j=hd[i];j;j=nxt[j]) 49 ans=max(ans,f[i]*f2[poi[j]]);//枚举边数 50 printf("%d",ans); 51 return 0; 52 }