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 }
View Code

 

posted @ 2018-12-04 14:15  kafuuchino  阅读(184)  评论(0编辑  收藏  举报