您的位置:首页 > 理论基础 > 计算机网络

BZOJ1458: 士兵占领 最大流

2016-09-14 15:37 393 查看

1458: 士兵占领

Time Limit: 10 Sec  Memory Limit: 64 MB

Submit: 917  Solved: 515
[Submit][Status][Discuss]

Description

有一个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

题解:

题目显然可以用网络流来求解:
因为想要得到最少需要摆放的士兵,我们可以转化一下问题去求最多有多少个格子不能放
我们可以把所有列,所有行抽象成n+m个点,把每一行向源点连一条边
边权是:对于每一行看看有多少个位置可以放士兵(也就是假设每排可以放m个士兵,这排有x个地方不能放士兵,这排要求必须要放y,边权就是m-x-y),对于每一列也是同理。
然后我们再搜索整个棋盘,比如坐标(x,y)处可以放棋子,就将行x所代表的点和列y所代表的点连一条边,边权为1,跑最大流就可以了,最大流的意义就是最多能找到多少个点可以不放棋子
答案ans=(n*m-k-最大流)
#include<cstdio>
#include<queue>
#include<iostream>
#include<cstring>
using namespace std;
const int N=305;
const int M=40005;
const int inf=2100000000;
int C
,L
,n,m,k,nl
,nc
,ans,mp

;
int from[M],to[M],nxt[M],lj
,cnt=-1,w[M],pre
;
void add(int f,int t,int p)
{
cnt++;
to[cnt]=t;
nxt[cnt]=lj[f];
lj[f]=cnt;
w[cnt]=p;
cnt++;
to[cnt]=f;
nxt[cnt]=lj[t];
lj[t]=cnt;
w[cnt]=0;
}
int S,T,d
;
queue<int>Q;
bool bfs()
{
memset(d,0,sizeof(d));
d[0]=1;
Q.push(0);
while(!Q.empty())
{
int x=Q.front();
Q.pop();
for(int i=lj[x];i>=0;i=nxt[i])
if(w[i]&&!d[to[i]])
{
d[to[i]]=d[x]+1;
Q.push(to[i]);
}
}
if(d[T]) return true;
return false;
}
int dfs(int x,int v)
{
if(x==T||v==0) return v;
int ret=0;
for(int i=lj[x];i>=0;i=nxt[i])
if(d[to[i]]==d[x]+1)
{
int f=dfs(to[i],min(w[i],v));
w[i]-=f;
w[i^1]+=f;
v-=f;
ret+=f;
if(v==0) break;
}
return ret;
}
void make()
{
for(int i=1;i<=n;i++) add(S,i,m-L[i]-nl[i]);
for(int i=1;i<=m;i++) add(i+n,T,n-C[i]-nc[i]);
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
if(!mp[i][j]) add(i,j+n,1);
}
int main()
{
scanf("%d%d%d",&n,&m,&k);
S=0,T=n+m+1;
for(int i=S;i<=T;i++) lj[i]=-1;
for(int i=1;i<=n;i++) scanf("%d",&L[i]);
for(int i=1;i<=m;i++) scanf("%d",&C[i]);
for(int i=1;i<=k;i++)
{
int x,y;
scanf("%d%d",&x,&y);
nl[x]++,nc[y]++;
mp[x][y]=1;
}
make();
for(int i=0;i<=cnt;i++)
if(w[i]<0)
{
printf("JIONG");
return 0;
}
while(bfs()) ans+=dfs(S,inf);
printf("%d",n*m-k-ans);
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  BZOJ 网络流