zoukankan      html  css  js  c++  java
  • 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("
    ");
     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
    ");
    121     else{
    122         c3=Dinic();
    123         if(c3!=c2) printf("No
    ");
    124         else{
    125             printf("Yes
    ");
    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 }
  • 相关阅读:
    SharePoint 2010学习笔记之一:创建”最新动态”WebPart
    IE6 Png 图片透明
    C# Url 过滤特殊字符
    委托的几个实例用法
    MVC中Code First编程一些小技巧
    Javascript 学习
    NET下XML的读写操作
    C#位运算讲解与示例[转]
    DB2导入导出命令(工作中使用)
    上海长期招聘c#/c++软件工程师
  • 原文地址:https://www.cnblogs.com/demian/p/9193735.html
Copyright © 2011-2022 走看看