【sgu176】有源汇有上下界的最大/最小流

题目链接:http://acm.hust.edu.cn/vjudge/problem/viewProblem.action?id=11025

 

题目大意:有一个类似于工业加工生产的机器,起点为1终点为n,中间生产环节有货物加工数量限制,输出u v z c, 当c等于1时表示这个加工的环节必须对纽带上的货物全部加工(即上下界都为z),c等于0表示加工没有上界限制,下界为0,求节点1(起点)最少需要投放多少货物才能传送带正常工作。

 

解题思路:经典题目,有上下界的最小流。

   1、du[i]表示i节点的入流之和与出流之和的差。 

   2、增设超级源点st和超级汇点sd,连(st,du[i](为正)),(-du[i](为负),sd)。 ///增设超级源点和超级汇点,因为网络中规定不能有弧指向st,也不能有流量流出sd

   3、做一次maxflow()。

   4、源点(Sd)和起点(St)连一条容量为oo的边。

   5、再做一次maxflow()。

   6、当且仅当所有附加弧满载时有可行流,最后答案为flow[(Sd-St)^1],St到Sd最大流就是Sd到St最小流。

View Code
  1 #include <iostream>

  2 #include <cstdio>

  3 #include <cmath>

  4 #include <algorithm>

  5 #include <cstring>

  6 using namespace std;

  7 

  8 const int mn=111;

  9 const int mm=11111;

 10 const int oo=0x3fffffff;

 11 int node, st, sd, edge, St, Sd, Edge;

 12 int reach[mm], flow[mm], next[mm];

 13 int head[mn], work[mn], dis[mn], que[mn];

 14 int du[mm], ans[mm], id[mm], dn[mm];

 15 

 16 inline void init(int _node, int _st, int _sd)

 17 {

 18     node=_node, st=_st, sd=_sd;

 19     for(int i=0; i<node; i++)

 20         head[i]=-1, du[i]=0;

 21     edge=0;

 22 }

 23 

 24 inline void addedge(int u, int v, int c1, int c2, int ID)

 25 {

 26     id[edge]=ID, reach[edge]=v, flow[edge]=c1, next[edge]=head[u],head[u]=edge++;

 27     id[edge]=0, reach[edge]=u, flow[edge]=c2, next[edge]=head[v],head[v]=edge++;

 28 }

 29 

 30 bool bfs()

 31 {

 32     int u, v, l=0, h=0;

 33     for(int i=0; i<node; i++) dis[i]=-1;

 34     que[l++]=st;

 35     dis[st]=0;

 36     while(l!=h)

 37     {

 38         u=que[h++];

 39         if(h==mn) h=0;

 40         for(int i=head[u]; i>=0; i=next[i])

 41         {

 42             v=reach[i];

 43             if(flow[i]&&dis[v]<0)

 44             {

 45                 dis[v]=dis[u]+1;

 46                 que[l++]=v;

 47                 if(l==mn) l=0;

 48                 if(v==sd) return true;

 49             }

 50         }

 51     }

 52     return false;

 53 }

 54 

 55 int dfs(int u, int exp)

 56 {

 57     if(u==sd) return exp;

 58     for(int &i=work[u]; i>=0; i=next[i])

 59     {

 60         int v=reach[i], tp;

 61         if(flow[i]&&dis[v]==dis[u]+1&&(tp=dfs(v,min(flow[i],exp))>0))

 62         {

 63             flow[i]-=tp;

 64             flow[i^1]+=tp;

 65             return tp;

 66         }

 67     }

 68     return 0;

 69 }

 70 

 71 void Dinic()

 72 {

 73     int max_flow=0, flow;

 74     while(bfs())

 75     {

 76         for(int i=0; i<node; i++) work[i]=head[i];

 77         while(flow=dfs(st,oo)) max_flow+=flow;

 78     }

 79 }

 80 

 81 int main()

 82 {

 83     int n, m;

 84     while(~scanf("%d%d",&n,&m))

 85     {

 86         init(n+1,1,n);

 87         for(int i=1; i<=m; i++)

 88         {

 89             int u, v, c, k;

 90             scanf("%d%d%d%d",&u,&v,&c,&k);

 91             if(k) du[u]-=c, du[v]+=c, ans[i]=c;

 92             else addedge(u,v,c,0,i);

 93         }

 94         St=st, Sd=sd, Edge=edge;

 95         st=node, sd=node+1, node+=2;    ///增设超级源点和超级汇点,因为网络中规定不能有弧指向st,也不能有流量流出sd

 96         head[st]=head[sd]=-1;

 97         for(int i=1; i<=n; i++)

 98         {

 99             if(du[i]>0) addedge(st,i,du[i],0,0);

100             if(du[i]<0) addedge(i,sd,-du[i],0,0);

101         }

102         Dinic();

103         addedge(Sd,St,oo,0,0);

104         Dinic();

105         bool flag=true;

106         for(int i=head[st]; i>=0; i=next[i])

107             if(flow[i]>0)   ///当且仅当附加弧达到满负载有可行流

108             {

109                 flag=false;

110                 break;

111             }

112         if(!flag)

113             puts("Impossible");

114         else

115         {

116             int res=0, i;

117             for(i=head[Sd]; i>=0; i=next[i])

118               if(reach[i]==St) break;

119             res=flow[i^1];

120             printf("%d\n",res);

121             for(i=0; i<Edge; i++) ans[id[i]]=flow[i^1];

122             for(i=1; i<=m; i++)

123             {

124                 if(i!=m) printf("%d ",ans[i]);

125                 else printf("%d\n",ans[i]);

126             }

127         }

128     }

129     return 0;

130 }

 

你可能感兴趣的:(流)