zoukankan      html  css  js  c++  java
  • 有上下界的网络流

    解决上下界网络流的一般思路:

      解决这类问题的关键是如何去掉下界带来的麻烦。下面的哈工大出版的《图论及应用》里的思路。

    1、网络的必要弧和构建附加网络

     

    前一个数是下界,后一个数是上界。

     

     

    下面的边是必要弧,其权值为下界。上面的边容量为上界与下界的差。

     

     

    添加附加源点Y,附加汇点X (别弄错了) <X , Y>为的权值正无穷。对于必要弧<u , v>,添加<u,Y>,<Y,v>,容量为必要弧的容量。

     

     

    删除<X, Y>,添加<T, S>,容量为正无穷。这样必要弧满流转化为最大流能够占满与Y相连的所有的边,同样占满所有与X相连的边。

     最后这一幅图就是我们解这类问题的构图方法了。对照题目,可以发现,这种题目的构图方式几乎定死了。

     

    2、解题的步骤

    (1)定义数据结构

    需要最大流的模版,存图方式一样(链式前向星),容量c = up - b (上界减去下界)

    定义low[]记录边的容量下界。 

    定义两个数组out[]in[]分别记录每个点的所有出边的下界之和以及所有入边的下界之和(可以通过一个数组来完成,因为我们只想知道这个点到底是流出去还是流进来)。

    S为源点,T为汇点。

    (2)附加网络

    加入虚拟源点SS和虚拟汇点TT。加入边<T, S> ,容量为正无穷。

    对于原图中的每个点i(包括源点S和汇点T),如果in[i]>out[i],则加边<SS,i>,容量为in[i]-out[i] ,如果in[i]<out[i],则加边<i,TT>,容量为out[i]-in[i]

    (3)判断有无解

    设所有边的下界的和为sum,如果SSTT的最大流不等于sum,就无解。

    还有其他判断方法,比如说判断以SS为起点的边的容量是否全部为0

    (4)去边

    第(2)步中加的边。对于<T, S >,增加权值为负无穷的<T ,S >就可以了。对于SS,TT的边,另head[SS] = head[TT] =-1就好了。

    (5)求最大流(最小流)

    最大流:去边以后运行ST的最大流算法。

    最小流:去边以后运行TS的最大流算法。

    每条边的流值等于flow(u,v) + low(u,v)。这个有多种计算方法。网上比较流行的方法是先加题目中输入的边(每个加的是两条),我们用一个数组low[]记录第一条边的下界。最后输出的答案是low[i] + edge[2*i+1].c 。当然下标是从0开始的。edge[2*i+1].c 需要解释一下,当算法运行以后,edge[2*i].c 都为0了,不然就无解。edge[2*i+1].cedge[2*i]的反向弧的权值,刚开始是0,但是算法运行完毕就等于原本的edge[2*i+1].c了。

      

    3、习题

    zoj2314 与sgu194本质上是同一题

    题解看别人的。http://www.cnblogs.com/kane0526/archive/2013/04/05/3001108.html

    代码自己的,用的SAP。

      1 #include<iostream>
      2 #include<cstdio>
      3 #include<cstring>
      4 #include<algorithm>
      5 using namespace std;
      6 const int N=210;
      7 const int M=100000, INF=0x3f3f3f3f;
      8 struct node
      9 {
     10     int to,next,w;
     11 }edge[M];
     12 int head[N],numh[N],h[N],cure[N],pre[N];
     13 int ans,tot;
     14 int od[N],ind[N],low[M];//出边下界之和、入边
     15 void SAP(int s, int e,int n)
     16 {
     17     int flow,u,tmp,neck,i;
     18     ans=0;
     19     for(i=1;i<=n;i++)
     20         cure[i]=head[i];
     21     numh[0]=n;
     22     u=s;
     23     while(h[s]<n)
     24     {
     25         if(u==e)
     26         {
     27             flow =INF;
     28             for(i=s;i!=e;i=edge[cure[i]].to)
     29             {
     30                 if(flow>edge[cure[i]].w)
     31                 {
     32                     neck=i;
     33                     flow =edge[cure[i]].w;
     34                 }
     35             }
     36             for(i=s;i!=e;i=edge[cure[i]].to)
     37             {
     38                 tmp=cure[i];
     39                 edge[tmp].w-=flow;
     40                 edge[tmp^1].w+=flow;
     41             }
     42             ans+=flow;
     43             u=neck;
     44         }
     45         for(i=cure[u];i!=-1;i=edge[i].next)
     46             if(edge[i].w && h[u]==h[edge[i].to]+1) break;
     47         if(i!=-1) {cure[u]=i;pre[edge[i].to]=u;u=edge[i].to;}
     48         else
     49         {
     50             if(0==--numh[h[u]]) break;
     51             cure[u]=head[u];
     52             for(tmp=n,i=head[u];i!=-1;i=edge[i].next)
     53                 if(edge[i].w) tmp=min(tmp, h[edge[i].to]);
     54             h[u]=tmp+1;
     55             ++numh[h[u]];
     56             if(u!=s) u=pre[u];
     57         }
     58     }
     59 }
     60 void init()
     61 {
     62     tot=0;
     63     memset(head,-1,sizeof(head));
     64     memset(pre,-1,sizeof(pre));
     65     memset(h,0,sizeof(h));
     66     memset(numh,0,sizeof(numh));
     67     memset(ind,0,sizeof(ind));
     68     memset(od,0,sizeof(od));
     69     memset(low,0,sizeof(low));
     70 }
     71 void addedge(int i,int j,int w)
     72 {
     73     edge[tot].to=j;edge[tot].w=w;edge[tot].next=head[i];head[i]=tot++;
     74     edge[tot].to=i;edge[tot].w=0;edge[tot].next=head[j];head[j]=tot++;
     75 }
     76 int main()
     77 {
     78     //freopen("test.txt","r",stdin);
     79     int cas,i,j,k,n,m,a,b,s,e;
     80     scanf("%d",&cas);
     81     while(cas--)
     82     {
     83         scanf("%d%d",&n,&m);
     84         init();
     85         for(k=0;k<m;k++)
     86         {
     87             scanf("%d%d%d%d",&i,&j,&a,&b);
     88             addedge(i,j,b-a);
     89             od[i]+=a;  ind[j]+=a;
     90             low[k]=a;
     91         }
     92         s=n+1;e=s+1;
     93         for(i=1;i<=n;i++)
     94         {
     95             if(ind[i]>od[i]) addedge(s,i,ind[i]-od[i]);
     96             if(ind[i]<od[i]) addedge(i,e,od[i]-ind[i]);
     97         }
     98         SAP(s,e,e);
     99         int flag=1;
    100         for(k=head[s];k!=-1;k=edge[k].next)
    101         {
    102             if(edge[k].w>0)
    103             {
    104                 flag=0;
    105                 break;
    106             }
    107         }
    108         if(!flag) printf("NO
    ");
    109         else
    110         {
    111             printf("YES
    ");
    112             for(i=0;i<m;i++)
    113             {
    114                 printf("%d
    ",low[i]+edge[2*i+1].w);
    115             }
    116         }
    117         if(cas) printf("
    ");
    118     }
    119     return 0;
    120 }
    View Code

    zoj3229

    题解看别人的。http://www.cnblogs.com/wuyiqi/archive/2012/03/15/2398559.html  代码风格跟我类似

    我最开始用SAP算法,怎么也AC不了。zoj2314都可以的。我检查了几个小时,最后都崩溃了。最后实在没办法了,换了Dinic的模版,没有修改就AC了。无语了。他们的时间复杂度的级别是一样的,并且SAP用了Dinic的优化思想,为什么就没办法过呢?

    AC代码:

      1 #include<iostream>
      2 #include<cstdio>
      3 #include<cstring>
      4 #include<algorithm>
      5 using namespace std;
      6 const int N=2000;
      7 const int M=1000000, INF=100000000;
      8 struct node
      9 {
     10     int to,next,w;
     11 }edge[M];
     12 int level[N],que[N],head[N];
     13 int tot,ans;
     14 bool makelevel(int s, int t)
     15 {
     16     memset(level,0,sizeof(level));
     17     level[s]=1;
     18     int iq=0 , i, k, top;
     19     que[iq++]=s;
     20     for(i=0;i<iq;i++)
     21     {
     22         top=que[i];
     23         if(top==t) return 1;
     24         for(k=head[top];k!=-1;k=edge[k].next)
     25             if(!level[edge[k].to] && edge[k].w)
     26             {
     27                 que[iq++]=edge[k].to;
     28                 level[edge[k].to]=level[top]+1;
     29             }
     30     }
     31     return 0;
     32 }
     33 int DFS(int now, int maxf, int t)
     34 {
     35     if(now ==t) return maxf;
     36     int ret=0, f, k;
     37     for(k=head[now];k!=-1;k=edge[k].next)
     38     {
     39         if(edge[k].w && level[edge[k].to]==level[now]+1)
     40         {
     41             f=DFS(edge[k].to, min(maxf-ret,edge[k].w), t);
     42             edge[k].w-=f;
     43             edge[k^1].w+=f;
     44             ret+=f;
     45             if(ret==maxf) return ret;
     46         }
     47     }
     48     return ret;
     49 }
     50 void DINIC(int s, int t)
     51 {
     52     ans=0;
     53     while(makelevel(s,t)) ans+=DFS(s,INF,t);
     54 }
     55 void addedge(int i,int j,int w)
     56 {
     57     edge[tot].to=j;edge[tot].w=w;edge[tot].next=head[i];head[i]=tot++;
     58     edge[tot].to=i;edge[tot].w=0;edge[tot].next=head[j];head[j]=tot++;
     59 }
     60 int p[N] ,ind[N],low[100010];
     61 int main()
     62 {
     63     //freopen("test.txt","r",stdin);
     64     int i,j,k,n,m,a,b,s,e,res,cnt,g;
     65     while(scanf("%d%d",&n,&m)!=EOF)
     66     {
     67         tot=0;
     68         memset(head,-1,sizeof(head));
     69         memset(ind,0,sizeof(ind));
     70         s=n+m+1;e=s+1;//源点,汇点
     71         for(i=1;i<=m;i++)
     72         {
     73             scanf("%d",&g);
     74             ind[i+n]-=g; ind[e]+=g;
     75         }
     76         cnt=0;
     77         for(i=1;i<=n;i++)//n天
     78         {
     79             scanf("%d%d",&k,&p[i]);//该天最多给r人拍照,最多拍p张
     80             while(k--)
     81             {
     82                 scanf("%d%d%d",&j,&a,&b);
     83                 j+=n+1;
     84                 addedge(i,j,b-a);
     85                 ind[i]-=a; ind[j]+=a;
     86                 low[cnt++]=a;//第cnt条边的下界
     87             }
     88         }
     89         for(i=1;i<=n;i++) addedge(s,i,p[i]);
     90         for(i=1;i<=m;i++) addedge(i+n,e,INF);
     91 
     92         //原图构造完毕
     93         addedge(e,s,INF);
     94         int st=e+1,ed=st+1;//超级源点、超级汇点
     95         for(i=1;i<=n+m+2;i++)
     96         {
     97             if(ind[i]>0) addedge(st,i,ind[i]);
     98             if(ind[i]<0) addedge(i,ed,-ind[i]);
     99         }
    100         DINIC(st,ed);
    101         int flag=1;
    102         for(k=head[st];k!=-1;k=edge[k].next)
    103         {
    104             if(edge[k].w)
    105             {
    106                 flag=0;
    107                 break;
    108             }
    109         }
    110         if(!flag) printf("-1
    ");
    111         else
    112         {
    113             DINIC(s,e);
    114             addedge(e,s,-INF);//删除添加的边
    115             res=0;
    116             for(i=head[s];i!=-1;i=edge[i].next)
    117                 res+=edge[i^1].w;
    118             printf("%d
    ",res);
    119             for(i=0;i<cnt;i++)
    120             {
    121                 printf("%d
    ",low[i]+edge[2*i+1].w);
    122             }
    123         }
    124         printf("
    ");
    125     }
    126     return 0;
    127 }
    View Code
  • 相关阅读:
    在IE和Firfox获取keycode
    using global variable in android extends application
    using Broadcast Receivers to listen outgoing call in android note
    help me!virtual keyboard issue
    using iscroll.js and iscroll jquery plugin in android webview to scroll div and ajax load data.
    javascript:jquery.history.js使用方法
    【CSS核心概念】弹性盒子布局
    【Canvas学习笔记】基础篇(二)
    【JS核心概念】数据类型以及判断方法
    【问题记录】ElementUI上传组件使用beforeupload钩子校验失败时的问题处理
  • 原文地址:https://www.cnblogs.com/Potato-lover/p/4002823.html
Copyright © 2011-2022 走看看