土兵占领:二分答案,最大流

Description

有一个M * N的棋盘,有的格子是障碍。现在你要选择一些格子来放置一些土兵,一个格子里最多可以放置一个土兵,障碍格里不能放置土兵。

我们称这些土兵占领了整个棋盘当满足第i行至少放置了Li个土兵, 第j列至少放置了Cj个土兵。

现在你的任务是要求使用最少个数的土兵来占领整个棋盘。

n,m<=100

把“士”替换成“土”我是故意的不要告诉我啊啊啊啊啊

来自网络流专题,默认颓了标签。

因为直接做死掉了所以要二分答案。

关键在于怎么建图。

NC说他没什么印象因为这道题切的太快了,然而我想了好半天。。。。

一些失败的想法:

把土兵放在左部,行列要求都放在右部,跑最大流。。。不行。。。每个兵会有2的流出很不好控制。。

把左右反过来也还是一样的。。。

所以我们考虑怎么把那个讨厌的2干掉。

那么如果关于行的我们设置为入边,关于列的设置为出边,这样就没有2了。

然后我们把行要求作为左部点,列要求作为中间点,土兵作为中间点。

这样的话必须保证右部满流,所以求解变成了检查,问题可以二分答案,而二分整个图的入流就是答案。

如果放满了土兵还达不到要求就是无解啦。。

但是我们可以发现,左边的行要求点是有最小限流的,流量不够就相当于没有满足要求。

所以有点像上下界网络流?但是我不会。

于是我开始自己YY,想到了再开一个新的超级源点,然后从它往左部点连等量于限制的边。

再把它与普通源点连(mid-总左部点要求)的边。

普通源点与左部点连inf的边,这样就满足了所有的要求。

其实就是上下界网络流的思想啦。。。

 1 #include<cstdio>
 2 #include<iostream>
 3 using namespace std;
 4 int m,n,k,x[111][111],cn,L[111],R[111],ord[111][111],Lord[111],Rord[111];
 5 int fir[16666],l[66666],to[66666],v[66666],cnt,dep[16666],q[16666];
 6 void link(int a,int b,int V){l[++cnt]=fir[a];fir[a]=cnt;to[cnt]=b;v[cnt]=V;}
 7 bool bfs(){
 8     for(int i=1;i<=cn;++i)dep[i]=1234567890;
 9     for(int h=1,t=1;h<=t;++h)for(int i=fir[q[h]];i;i=l[i])if(v[i]&&dep[to[i]]>dep[q[h]]+1)
10         dep[to[i]]=dep[q[h]]+1,q[++t]=to[i];
11     return dep[cn]!=1234567890;
12 }
13 int dfs(int p,int flow){
14     if(p==cn)return flow;int res=flow;
15     for(int i=fir[p];i;i=l[i])if(v[i]&&dep[to[i]]==dep[p]+1){
16         int r=dfs(to[i],min(flow,v[i]));
17         v[i]-=r;v[i^1]+=r;flow-=r;
18     }
19     return res-flow;
20 }
21 bool chk(int mid){int max_flow=0,goal=0;
22     for(int i=0;i<=cn;++i)fir[i]=0;cnt=1;
23     for(int i=1;i<=n;++i)link(0,Lord[i],L[i]),link(Lord[i],0,0),mid-=L[i];
24     if(mid<0)return false;
25     for(int i=1;i<=m;++i)link(Rord[i],cn,R[i]),link(cn,Rord[i],0),goal+=R[i];
26     for(int i=1;i<=n;++i)link(cn-1,Lord[i],1234567890),link(Lord[i],cn-1,0);
27     link(0,cn-1,mid);link(cn-1,0,0);
28     for(int i=1;i<=n;++i)for(int j=1;j<=m;++j)if(x[i][j]!=-1)
29         link(Lord[i],x[i][j],1),link(x[i][j],Lord[i],0),
30         link(x[i][j],Rord[j],1),link(Rord[j],x[i][j],0);
31     while(bfs())max_flow+=dfs(0,1234567890);
32     return max_flow==goal;
33 }
34 int main(){
35     scanf("%d%d%d",&n,&m,&k);
36     for(int i=1;i<=n;++i)scanf("%d",&L[i]),Lord[i]=++cn;
37     for(int i=1;i<=m;++i)scanf("%d",&R[i]),Rord[i]=++cn;
38     for(int i=1,a,b;i<=k;++i)scanf("%d%d",&a,&b),x[a][b]=-1;
39     for(int i=1;i<=n;++i)for(int j=1;j<=m;++j)if(x[i][j]!=-1)ord[i][j]=++cn;
40     cn+=2;
41     int l=0,r=n*m;
42     while(l<r-1)if(chk(l+r>>1))r=l+r>>1;else l=(l+r>>1)+1;
43     if(chk(l))printf("%d
",l);else if(chk(r))printf("%d
",r);else puts("JIONG!");
44 }
View Code
原文地址:https://www.cnblogs.com/hzoi-DeepinC/p/11579851.html