CDOJ 1962 天才钱vs学霸周2【最大流】

以s=0,t=n+m+1分别为超级源点和超级汇点。网络流中的流量以0为开始,题目要求从1到20,我们先把每个点都减去1,即ai - m,bi - n。然后源点s与n个顶点连容量为ai的路,汇点t与m个顶点连容量为bi的路,n个顶点再与m个顶点连接19的容量。最后再跑下Dinic,如果最后汇聚到t的流量和总值相同,输出“Yes”,否则输出“No”。最后输出对应边的答案,可以用残余网络来计算,用19-残余的容量即该条边的流量。

  1 #include <queue>
  2 #include <cstdio>
  3 #include <cstring>
  4 #include <iostream>
  5 #include <algorithm>
  6 using namespace std;
  7 
  8 const int N=100;
  9 const int M=N*N;
 10 const int INF = 0x3f3f3f3f;
 11 int s,t,n,m,cnt;
 12 int a[N],b[N];
 13 int Head[N],Depth[N],Next[M],V[M],W[M];
 14 
 15 void init()
 16 {
 17     cnt=-1;
 18     memset(Head,-1,sizeof(Head));
 19     memset(Next,-1, sizeof(Next));
 20 }
 21 
 22 void add_edge(int u,int v,int w)
 23 {
 24     cnt++;Next[cnt]=Head[u];V[cnt]=v;W[cnt]=w;Head[u]=cnt;
 25     cnt++;Next[cnt]=Head[v];V[cnt]=u;W[cnt]=0;Head[v]=cnt; // 反向边
 26 }
 27 
 28 bool bfs()
 29 {
 30     queue<int> q;
 31     while(!q.empty())q.pop();
 32     memset(Depth,0, sizeof(Depth));
 33     q.push(s);
 34     Depth[s]=1;
 35     while(!q.empty())
 36     {
 37         int u=q.front();q.pop();
 38         for(int i=Head[u];i!=-1;i=Next[i])
 39         {
 40             if(W[i]>0&&Depth[V[i]]==0)
 41             {
 42                 Depth[V[i]]=Depth[u]+1;
 43                 q.push(V[i]);
 44             }
 45         }
 46     }
 47     if(Depth[t]==0)return false;
 48     else return true;
 49 }
 50 
 51 int dfs(int u,int flow)
 52 {
 53     if(u==t)return flow;
 54     int rest = flow;
 55     for(int i=Head[u];i!=-1;i=Next[i])
 56     {
 57         if(Depth[V[i]]==Depth[u]+1&&W[i]>0)
 58         {
 59             int k=dfs(V[i],min(W[i],rest));
 60             if(!k)Depth[V[i]]=0;  // 剪枝,去掉增广完毕的点
 61             W[i]-=k;
 62             W[i^1]+=k;
 63             rest-=k;
 64         }
 65     }
 66     return flow-rest;
 67 }
 68 
 69 int Dinic()
 70 {
 71     int ans=0;
 72     while(bfs()) // 在残量网络上构造分层图
 73     {
 74         while(int flow = dfs(s,INF)) // 在当前分层图上增广
 75             ans+=flow;
 76     }
 77     return ans;
 78 }
 79 
 80 void print()
 81 {
 82     int res[N][N];
 83     memset(res,0,sizeof(res));
 84     for(int i=1;i<=n;i++)
 85         for(int j=Head[i];j!=-1;j=Next[j])
 86         {
 87             int v=V[j];
 88             if(v>n&&v<=n+m)res[i][v-n]=19-W[j]+1;
 89         }
 90     for(int i=1;i<=n;i++){
 91         for(int j=1;j<=m;j++){
 92             printf("%d",res[i][j]);
 93             if(j==m) printf("\n");
 94             else printf(" ");
 95         }
 96     }
 97 }
 98 
 99 int main(){
100     init();
101     scanf("%d%d",&n,&m);
102     s=0;t=n+m+1;
103 
104     for(int i=1;i<=n;i++){
105         scanf("%d",&a[i]);a[i]-=m;
106         add_edge(s,i,a[i]);
107     }
108     for(int i=1;i<=m;i++){
109         scanf("%d",&b[i]);b[i]-=n;
110         add_edge(n+i,t,b[i]);
111     }
112 
113     for(int i=1;i<=n;i++)
114         for(int j=1;j<=m;j++)
115             add_edge(i,n+j,19);
116 
117     int c1=0,c2=0,c3=0;
118     for(int i=1;i<=n;i++) c1+=a[i];
119     for(int i=1;i<=m;i++) c2+=b[i];
120     if(c1!=c2) printf("No\n");
121     else{
122         c3=Dinic();
123         if(c3!=c2) printf("No\n");
124         else{
125             printf("Yes\n");
126             print();
127         }
128     }
129     return 0;
130 }

附:Edmonds-Karp增广路算法模板: 不断用BFS寻找增广路,直至网络上不存在增广路为止

 1 const int inf = 1<<29,N=2010,M=20010;
 2 int head[N],ver[M],edge[M],Next[M],v[N],incf[N],pre[N];
 3 int n,m,s,t,tot,maxflow;
 4 
 5 void add(int x,int y,int z)
 6 {
 7     tot++,ver[tot]=y,edge[tot]=z,Next[tot]=head[x],head[x]=tot; // 邻接表的数组写法
 8     tot++,ver[tot]=x,edge[tot]=0,Next[tot]=head[y],head[y]=tot; //反向边,edge剩余容量
 9 }
10 
11 bool bfs()
12 {
13     memset(v,0, sizeof(v));
14     queue<int> q;
15     q.push(s);v[s]=1;
16     incf[s]=inf; // 增广路上个边的最小剩余容量
17     while(q.size())
18     {
19         int x = q.front();
20         q.pop();
21         for(int i=head[x];i;i=Next[i])
22         {
23             if(edge[i])
24             {
25                 int y=ver[i];
26                 if(v[y])continue;
27                 incf[y]=min(incf[x],edge[i]);
28                 pre[y]=i; // 记录前驱(当前的tot序号,偶奇成对存储,抑或操作可导出前驱)
29                 q.push(y);
30                 v[y]=1;
31                 if(y==t)return 1; // 可达t点
32             }
33         }
34     }
35     return 0;
36 }
37 
38 void update()// 更新一条增广路及其反向边的剩余容量
39 {
40     int x = t;
41     while(x!=s)
42     {
43         int i=pre[x];
44         edge[i]-=incf[t];
45         edge[i^1]+=incf[t];
46         x = ver[i^1]; // 前驱节点
47     }
48     maxflow+=incf[t];
49 }
50 
51 int main()
52 {
53     while(cin>>m>>n)
54     {
55         memset(head,0, sizeof(head));
56         s=1,t=n;tot=1;maxflow=0;
57         for(int i=1;i<=m;i++)
58         {
59             int x,y,c;
60             scanf("%d%d%d",&x,&y,&c);
61             add(x,y,c);
62         }
63         while(bfs())update();
64         cout<<maxflow<<endl;
65     }
66 }

 

posted @ 2018-06-17 21:21  demianzhang  阅读(254)  评论(0编辑  收藏  举报