[最大流] 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;}
阅读全文
0 0
- BZOJ 1458: 士兵占领 最大流 题解
- [最大流] BZOJ 1458: 士兵占领 题解
- BZOJ 1458 士兵占领 Dinic最大流
- 【bzoj 1458】士兵占领(最大流)
- BZOJ 1458: 士兵占领 网络最大流
- BZOJ 1458: 士兵占领 最大流
- 【bzoj 1458】士兵占领(最大流)
- 【BZOJ 1458】 士兵占领
- bzoj 1458: 士兵占领
- BZOJ 1458: 士兵占领
- bzoj 1458: 士兵占领 网络流
- 1458: 士兵占领 思路题 最大流
- BZOJ1458 士兵占领 最大流
- 【bzoj1458】士兵占领 最大流
- 【BZOJ1458】士兵占领【最大流】
- BZOJ1458: 士兵占领 最大流
- 【bzoj1458】士兵占领 最大流
- BZOJ1458 士兵占领-最大流
- 一起学Netty(五)之 初识ByteBuf和ByteBuf的常用API
- 移动架构23_设计模式六大原则一:单一职责原则
- 量子成像与量子雷达技术
- MySql的数据找回
- spring @component的作用
- [最大流] BZOJ 1458: 士兵占领 题解
- 如何杀死一个python的线程
- servlet3.0 part上传文件
- C++ 基础知识二
- Java 流(Stream)、文件(File)和IO
- Java的JSON取值工具类
- TensorFlow读取机制图解
- Linux 安装 .xz解压工具
- 获取函数参数arguments的方法