版权声明:本文为博主原创文章,未经博主允许必须转载。 https://blog.csdn.net/qq_35950004/article/details/88560228
有一个M * N的棋盘,有的格子是障碍。现在你要选择一些格子来放置一些士兵,一个格子里最多可以放置一个士兵,障碍格里不能放置士兵。我们称这些士兵占领了整个棋盘当满足第i行至少放置了Li个士兵, 第j列至少放置了Cj个士兵。现在你的任务是要求使用最少个数的士兵来占领整个棋盘。
最小流裸题。
连T->S成循环流,最小流为T到S的边的反向边的流量-T到S的最大流(需要删去T到S的边)
AC Code:
#include<bits/stdc++.h>
#define maxn 10005
#define maxm maxn*20
#define inf 0x3f3f3f3f
using namespace std;
int n,m,k,l[105],c[105];
bool mp[105][105];
int S,T,SS,TT,tot;
int info[maxn],Prev[maxm],to[maxm],cap[maxm],cnt_e=1;
void Node(int u,int v,int c){ Prev[++cnt_e]=info[u],info[u]=cnt_e,to[cnt_e]=v,cap[cnt_e]=c; }
void Line(int u,int v,int c){ Node(u,v,c),Node(v,u,0); }
int h[maxn],gap[maxn];
int aug(int now,int Max){
if(now == T) return Max;
int inc , st = Max;
for(int i=info[now];i;i=Prev[i])
if(cap[i] && h[to[i]]+1==h[now])
{ inc = aug(to[i],min(cap[i],st));
st-=inc,cap[i]-=inc,cap[i^1]+=inc;
if(!st || h[S]>tot) return Max-st;
}
if(!--gap[h[now]]) h[S] = tot+1;
++gap[++h[now]];
return Max-st;
}
int main()
{
scanf("%d%d%d",&n,&m,&k);SS = ++tot , TT = ++tot , S = ++tot, T = ++tot;
int s1 = 0 , s2 = 0 , stm = 0;
for(int i=1;i<=n;i++) scanf("%d",&l[i]),Line(S,++tot,m),Line(SS,tot,l[i]),s1+=l[i];
for(int i=1;i<=m;i++) scanf("%d",&c[i]),Line(++tot,T,n),Line(tot,TT,c[i]),s2+=c[i];
Line(S,TT,s1),Line(SS,T,s2),stm+=s1+s2;
for(int i=1,u,v;i<=k;i++) scanf("%d%d",&u,&v),mp[u][v]=1;
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
if(!mp[i][j])
{
++tot;
Line(T+i,tot,1);
Line(tot,T+n+j,1);
}
Line(T,S,inf);
S = SS , T = TT;
for(gap[0]=tot;h[S]<=tot;)
stm-=aug(S,inf);
if(stm) puts("JIONG!");
else{
stm=cap[cnt_e],cap[cnt_e]=cap[cnt_e-1]=0;
memset(h,0,sizeof h);
memset(gap,0,sizeof gap);
S = 4 , T = 3;
for(gap[0]=tot-2;h[S]<=tot-2;)
stm-=aug(S,inf);
printf("%d\n",stm);
}
}