有上下界的网络流

以下摘自Proverbs的博客:

1. 首先进行构图,对于那么对流量没有限制的边,我们直接将容量赋值为原始的容量,而对于有流量要求的边,我们将容量减去下界并将其等价与无下界的边。

2. 添加一个附加汇点和一个附加源点,从附加源点连向每个顶点的容量为以该点所有流入的下界流量总和,每个顶点流向附加汇点是该点流出的下界流量总和。

3. 添加一条从汇点到源点流量为INF的边,这条边的意义在于,能够使得源点会汇点满足成为流量平衡条件的普通节点。

4. 我们在以附加源点和附加汇点求一次最大流,如果所有的到附加汇点的边都满载,那么说明这个网络是存在满足所有下界的可行流的。

  1 #include<cstdio>
  2 #include<cstring>
  3 #include<algorithm>
  4 using std::min;
  5 using std::max;
  6 #define M 100000
  7 #define N 1000
  8 #define INF 210000000
  9 #define rep(i,n) for(int i=1;i<=(n);i++)
 10 #define mem(a) memset(a,0,sizeof(a))
 11 int len[M <<1],e[M <<1],nex[M <<1],other[M <<1],head[N],last[N],d[N],num[N];
 12 int rdu[N],cdu[N],_,eee,flag,y,k,l,opt,S,T,m,n,ans,tot,ss,tt,ee,x,uu[250][250],dd[250][250];
 13 int an[250][250];
 14 char c;
 15 struct lbz
 16 {
 17     int u,v,l,r;
 18 }a[N];
 19 void init()
 20 {
 21     memset(head,0,sizeof(head));
 22     memset(num,0,sizeof(num));
 23     memset(d,0,sizeof(d));
 24     mem(cdu);
 25     mem(rdu);
 26     rep(i,n)
 27         rep(j,m)
 28         {
 29             uu[i][j]=INF;
 30             dd[i][j]=0;
 31         }
 32     flag=ans=ee=eee=0;
 33 }
 34 void add(int u,int v,int c)
 35 {
 36     //printf("%d %d %d
",u,v,c);
 37     other[++ee]=ee+1;
 38     e[ee]=v;nex[ee]=head[u];head[u]=ee;len[ee]=c;
 39     other[++ee]=ee-1;
 40     e[ee]=u;nex[ee]=head[v];head[v]=ee;len[ee]=0;
 41 }
 42 int dfs(int x,int flow)
 43 {
 44     int rec,j,p;
 45     if (x==tt) return flow;
 46     rec=0;j=last[x];
 47     while (j!=0)
 48     {
 49         if (len[j]>0 && d[x]==d[e[j]]+1)
 50         {
 51             last[x]=j;
 52             p=dfs(e[j],min(len[j],flow-rec));
 53             len[j]-=p;len[other[j]]+=p;
 54             rec+=p;
 55             if (rec==flow) return rec;
 56         }
 57     j=nex[j];
 58     }
 59     if (d[ss]>tot) return rec;
 60      if (--num[d[x]]==0) d[ss]=tot;
 61      last[x]=head[x];
 62      num[++d[x]]++;
 63      return rec;
 64 }
 65 void deal(int x,int y)
 66 {
 67     if (c=='>')
 68         dd[x][y]=max(dd[x][y],k+1);
 69     if (c=='<')
 70         uu[x][y]=min(uu[x][y],k-1);
 71     if (c=='=')
 72     {
 73         if (k<dd[x][y]||k>uu[x][y])
 74             flag=1;
 75         dd[x][y]=uu[x][y]=k;
 76     }
 77     if (uu[x][y]<dd[x][y])
 78         flag=1;
 79 }
 80 void add1(int u,int v,int l,int r)
 81 {
 82     eee++;
 83     a[eee].u=u;a[eee].v=v;
 84     a[eee].l=l;a[eee].r=r;
 85     rdu[v]+=l;cdu[u]+=l;
 86 }
 87 int main()
 88 {
 89     scanf("%d",&_);
 90     int __=_;
 91     while (_--)
 92     {
 93         if (__!=_-1)    puts("");
 94         scanf("%d%d",&n,&m);
 95         init();
 96         S=2;T=n+m+3;
 97         rep(i,n)
 98         {
 99             scanf("%d",&l);
100             add1(S,i+2,l,l);
101         }
102         rep(i,m)
103         {    
104             scanf("%d",&l);
105             add1(n+i+2,T,l,l);
106         }
107         scanf("%d",&opt);
108         while (opt--)
109         {
110             scanf("%d%d %c %d",&x,&y,&c,&k);
111             if (x==0&&y==0)
112             {
113                 rep(i,n)
114                     rep(j,m)
115                         deal(i,j);
116                 continue;
117             }
118             if (x==0)
119             {
120                 rep(i,n)
121                     deal(i,y);
122                 continue;
123             }
124             if (y==0)
125             {
126                 rep(i,m)
127                     deal(x,i);
128                 continue;
129             }
130             deal(x,y);
131         }
132         if (flag==1)
133         {
134             printf("IMPOSSIBLE
");
135             continue;
136         }
137         rep(i,n)
138             rep(j,m)
139             {
140                 add1(i+2,j+2+n,dd[i][j],uu[i][j]);
141             }
142         ss=S-1;tt=T+1;
143         rep(i,eee)
144             add(a[i].u,a[i].v,a[i].r-a[i].l);
145         for (int i=S;i<=T;i++)
146         {
147             add(ss,i,rdu[i]);
148             add(i,tt,cdu[i]);
149         }        
150         add(T,S,INF);
151 
152         tot=num[0]=tt;
153         for (int i=ss;i<=tt;i++)
154             last[i]=head[i];
155         while (d[ss]<tot)
156             ans+=dfs(ss,2147483647);
157         //printf("%d
",ans);
158         int j=head[ss];
159         while (j>0)
160         {
161             if (len[j]>0)
162                 flag=1;
163             j=nex[j];
164         }
165         if (flag==1)
166         {
167             printf("IMPOSSIBLE
");
168             continue;
169         }
170         for (int i=3;i<=2+n;i++)
171         {
172             int j=head[i];
173             while (j>0)
174             {
175                 an[i-2][e[j]-n-2]=dd[i-2][e[j]-n-2]+len[other[j]];
176                 j=nex[j];
177             }
178         }
179         rep(i,n)
180         {
181             rep(j,m-1)
182                 printf("%d ",an[i][j]);
183             printf("%d
",an[i][m]);
184         }
185                 
186     }
187     return 0;
188 }
栗题poj2396

以下摘自Edelweiss《网络流建模汇总》

发散思维:
1. 怎样求无源汇有上下界网络的可行流?
由于有源汇的网络我们先要转化成无源汇,所以本来就无源汇的网络不用再作特殊处理。
2. 怎样求无源汇有上下界网络的最大流、最小流?
一种简易的方法是采用二分的思想,不断通过可行流的存在与否对(t, s)边的上下界U, L进行调整。求最大流时令U = ∞并二分L;求最小流时令L = 0并二分U。道理很简单,因为可行流的取值范围是一段连续的区间,我们只要通过二分找到有解和无解的分界线即可。

------------------------------------------------------------------------- 花有重开日,人无再少年
原文地址:https://www.cnblogs.com/lbz007oi/p/6039692.html