[最大流] BZOJ 1458: 士兵占领 题解

来源:互联网 发布:js post 请求 ajax 编辑:程序博客网 时间:2024/05/20 09:22

本题有权限……
1458: 士兵占领

时限: 10s
空间上限: 64 MB

题目描述

有一个M * N的棋盘,有的格子是障碍。现在你要选择一些格子来放置一些士兵,一个格子里最多可以放置一个士兵,障碍格里不能放置士兵。我们称这些士兵占领了整个棋盘当满足第i行至少放置了Li个士兵, 第j列至少放置了Cj个士兵。现在你的任务是要求使用最少个数的士兵来占领整个棋盘。

Input

第一行两个数M, N, K分别表示棋盘的行数,列数以及障碍的个数。 第二行有M个数表示Li。 第三行有N个数表示Ci。 接下来有K行,每行两个数X, Y表示(X, Y)这个格子是障碍。

Output

输出一个数表示最少需要使用的士兵个数。如果无论放置多少个士兵都没有办法占领整个棋盘,输出”JIONG!” (不含引号)

Sample Input

4 4 4
1 1 1 1
0 1 0 3
1 4
2 2
3 3
4 3

Sample Output

4

数据范围

M, N <= 100, 0 <= K <= M * N

首先容易想到如何判断无解,把棋盘上能放的放,看一下是否合法,然后可以沿这个思路走下去,看最多能拿多少。

网络流建模,源点向所有行连边,容量上限为最多能拿走多少,所有列连边,容量上限同样为最多能拿走多少。所有能放的格子所在行列连一边,容量为1。Dinic模板AC。

#include<cstdio>#include<cstring>#include<cstdlib>#include<algorithm>using namespace std;const int INF=(((1<<30)-1)<<1)+1;int n,m,k,tot,ans,sum,s,t,son[20005],nxt[20005],cap[20005],flow[20005],lnk[205],que[205],dst[205],lst[205],a[105],b[105];bool mp[105][105],vs[205];inline void readi(int &x){    x=0; char ch=getchar();    while ('0'>ch||ch>'9') ch=getchar();    while ('0'<=ch&&ch<='9') {x=x*10+ch-'0'; ch=getchar();}}void _add(int x,int y,int z){    tot++; son[tot]=y; nxt[tot]=lnk[x]; cap[tot]=z; flow[tot]=0; lnk[x]=tot;    tot++; son[tot]=x; nxt[tot]=lnk[y]; cap[tot]=0; flow[tot]=0; lnk[y]=tot;}void _write(){printf("JIONG!"); exit(0);}bool _bfs(){    memset(vs,0,sizeof(vs));    memset(dst,0,sizeof(dst));    int hed=0,til=1; que[1]=s; vs[s]=true; dst[s]=1;    while (hed!=til){        int x=que[++hed];        for (int j=lnk[x];j;j=nxt[j])            if (!vs[son[j]]&&cap[j]>flow[j]){                que[++til]=son[j];                dst[son[j]]=dst[x]+1;                vs[son[j]]=true;            }    }    return vs[t];}int _dfs(int x,int now){    if (!now||x==t) return now; int sum=0;    for (int j=lst[x];j;lst[x]=j=nxt[j])        if (dst[son[j]]==dst[x]+1){            int tem=_dfs(son[j],min(now,cap[j]-flow[j]));            if (tem){                sum+=tem; now-=tem; flow[j]+=tem; flow[j^1]-=tem;                if (!now) break;            }        }    return sum;}int _Dinic(){    ans=0;    while (_bfs()){        for (int i=1;i<=t;i++) lst[i]=lnk[i];        ans+=_dfs(s,INF);    }    return ans;}int main(){    freopen("soldier.in","r",stdin);     freopen("soldier.out","w",stdout);    readi(n); readi(m); readi(k); tot=1; s=n+m+1; t=s+1;    memset(mp,1,sizeof(mp));    memset(lnk,0,sizeof(lnk));    for (int i=1;i<=n;i++) readi(a[i]);    for (int i=1;i<=m;i++) readi(b[i]);    for (int i=1,x,y;i<=k;i++){        readi(x); readi(y); mp[x][y]=0;    }    for (int i=1;i<=n;i++){        int tem=0;        for (int j=1;j<=m;j++) tem+=mp[i][j];        if (tem<a[i]) _write();        _add(s,i,tem-a[i]);    }    for (int j=1;j<=m;j++){        int tem=0;        for (int i=1;i<=n;i++) tem+=mp[i][j];        if (tem<b[j]) _write();        _add(j+n,t,tem-b[j]);    }    for (int i=1;i<=n;i++)        for (int j=1;j<=m;j++)            if (mp[i][j]){_add(i,j+n,1); sum++;}    printf("%d",sum-_Dinic());    return 0;}