BZOJ1458: 士兵占领 最大流
2016-09-14 15:37
393 查看
1458: 士兵占领
Time Limit: 10 Sec Memory Limit: 64 MBSubmit: 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 41 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); }
相关文章推荐
- Poj2638 网络流+最短路+二分答案
- BZOJ3275 Number (最小割)
- BZOJ2809——[Apio2012]dispatching
- BZOJ2809——[Apio2012]dispatching
- [笔记] 网络流-最大流 POJ-1273\HDU-4240
- 上下界网络流初探
- Edmonds-Karp 最大流 hdu 1532 Drained Ditches
- bzoj1088[SCOI2005]扫雷
- bzoj1086[SCOI2005]王室联邦
- dinic算法实现
- 网络流_poj1273
- POJ 1273 Drainage Ditches 最大流 dinic
- [BZOJ1087][SCOI2005]互不侵犯King(状压)[第二题]
- POJ1273-Drainage Ditches
- 【网络流】复杂的大门
- ACM/ICPC World Finals 2013 C Surely You Congest
- 北京集训队 2016 Day4 alarm
- [bzoj1003] [ZJOI2006]物流运输trans
- 网络流算法整理
- 【题解】dutoj1082 埃蒙的时空航道