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
  • 相关阅读:
    大数据应用期末总评
    分布式文件系统HDFS 练习
    安装Hadoop
    爬虫综合大作业
    爬取全部的校园新闻
    理解爬虫原理
    中文词频统计与词云生成
    复合数据类型,英文词频统计
    字符串操作、文件操作
    了解大数据的特点、来源与数据呈现方式
  • 原文地址:https://www.cnblogs.com/Potato-lover/p/4002823.html
Copyright © 2011-2022 走看看