Description
有一个M * N的棋盘,有的格子是障碍。现在你要选择一些格子来放置一些土兵,一个格子里最多可以放置一个土兵,障碍格里不能放置土兵。
我们称这些土兵占领了整个棋盘当满足第i行至少放置了Li个土兵, 第j列至少放置了Cj个土兵。
现在你的任务是要求使用最少个数的土兵来占领整个棋盘。
n,m<=100
把“士”替换成“土”我是故意的不要告诉我啊啊啊啊啊
来自网络流专题,默认颓了标签。
因为直接做死掉了所以要二分答案。
关键在于怎么建图。
NC说他没什么印象因为这道题切的太快了,然而我想了好半天。。。。
一些失败的想法:
把土兵放在左部,行列要求都放在右部,跑最大流。。。不行。。。每个兵会有2的流出很不好控制。。
把左右反过来也还是一样的。。。
所以我们考虑怎么把那个讨厌的2干掉。
那么如果关于行的我们设置为入边,关于列的设置为出边,这样就没有2了。
然后我们把行要求作为左部点,列要求作为中间点,土兵作为中间点。
这样的话必须保证右部满流,所以求解变成了检查,问题可以二分答案,而二分整个图的入流就是答案。
如果放满了土兵还达不到要求就是无解啦。。
但是我们可以发现,左边的行要求点是有最小限流的,流量不够就相当于没有满足要求。
所以有点像上下界网络流?但是我不会。
于是我开始自己YY,想到了再开一个新的超级源点,然后从它往左部点连等量于限制的边。
再把它与普通源点连(mid-总左部点要求)的边。
普通源点与左部点连inf的边,这样就满足了所有的要求。
其实就是上下界网络流的思想啦。。。
1 #include2 #include 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 1)if(chk(l+r>>1))r=l+r>>1;else l=(l+r>>1)+1; 43 if(chk(l))printf("%d\n",l);else if(chk(r))printf("%d\n",r);else puts("JIONG!"); 44 }