BZOJ 1458: 士兵占领
2016-03-03 17:03
363 查看
BZOJ 1458: 士兵占领
标签(空格分隔): OI BZOJ 上下界网络流 最小流Time Limit: 10 Sec
Memory Limit: 64 MB
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
Solution
诶省选一试前最后一个晚上调这个搞到11点,因为n、m反了,我的程序里n、m与题目意义相反建立M个点 \(A_i\)表示行的放置数量,N个点\(B_j\)表示列的放置数量。
S向\(A_i\)连一条下界为\(L_i\),上界无穷大的边;
\(B_j\)向T连一条下界为\(C_j\),上界无穷大的边。
若(i,j)可以放置士兵则在\(A_i、B_j\)间连一条上界为1下界为0的边。
跑一边上下界最小流即可
上下界网络流
新建超级源SS,超级汇TT。
设点i的入边下界和为\(In_i\)
设点i的出边下界和为\(Out_i\)
SS向i连上界为\(In_i\),i向TT连上界为\(Out_i\)的边
对原图中的边,设上界为up,下界为down,则改为残余网络,即下界为0,上界为up-down
T向S连一条上界无穷大的边
SS向TT跑一边最大流得到可行流
T到S的边的流量为原图的总流量
为了使总流量最小所以要使得\(E_{T->S}\)最小。删除边T->S,尽量退流,即跑一遍T
Code
#include<iostream> #include<stdio.h> #include<math.h> #include<stdlib.h> #include<string.h> #include<algorithm> #include<queue> using namespace std; int read() { int s=0,f=1;char ch=getchar(); while(!('0'<=ch&&ch<='9')){if(ch=='-')f=-1;ch=getchar();} while('0'<=ch&&ch<='9'){s=(s<<3)+(s<<1)+ch-'0';ch=getchar();} return s*f; } int S,T,SS,TT,n,m,K,np; int A[105],B[105],jr[10005],jc[10005]; int be[100005],bn[200005],bv[200005],bl[200005],bw=1; void put(int u,int v,int l) {bw++;bn[bw]=be[u];be[u]=bw;bv[bw]=v;bl[bw]=l;} int d[100005]; bool spfa(int S,int T) { for(int i=1;i<=np;i++) d[i]=10000000; d[S]=1; queue<int>q; for(q.push(S);!q.empty();) {int u=q.front();q.pop(); for(int i=be[u],v;i;i=bn[i]) if(d[v=bv[i]]>d[u]+1&&bl[i]) {d[v]=d[u]+1; q.push(v); } } return d[T]!=10000000; } int ans; int dinic(int u,int mf,int T) { if(mf==0)return 0; if(u==T)return mf; int sum=0; for(int i=be[u],v;i;i=bn[i]) if(d[v=bv[i]]==d[u]+1) {int f=dinic(v,min(mf-sum,bl[i]),T); bl[i]-=f; bl[i^1]+=f; sum+=f; } return sum; } bool p[101][101]; int main() { m=read(),n=read(),K=read(); S=++np,T=++np; for(int i=1;i<=m;i++) {int l=read(); put(S,A[i]=++np,1e9); put(A[i],S,0); jr[np]+=l; jc[S]+=l; } for(int i=1;i<=n;i++) {int l=read(); put(B[i]=++np,T,1e9); put(T,B[i],0); jc[np]+=l; jr[T]+=l; } for(int i=1;i<=K;i++) {int x=read(),y=read();p[x][y]=1;} for(int i=1;i<=m;i++) for(int j=1;j<=n;j++) if(p[i][j]==0) put(A[i],B[j],1),put(B[j],A[i],0); SS=++np,TT=++np; int sumr=0; for(int i=1;i<=np;i++) {if(jr[i]-jc[i]>0)put(SS,i,jr[i]-jc[i]),put(i,SS,0),sumr+=jr[i]-jc[i]; else put(i,TT,jc[i]-jr[i]),put(TT,i,0); } put(T,S,1e9); put(S,T,0); while(spfa(SS,TT))ans+=dinic(SS,1e9,TT); if(ans<sumr) {printf("JIONG!\n");return 0;} ans=bl[bw]; bl[bw]=bl[bw-1]=0; while(spfa(T,S))ans-=dinic(T,1e9,S); printf("%d\n",ans); return 0; }
相关文章推荐
- 在线编程题
- 关于小话C语言集合贴,C 语言常见问题集,c语言-优化C代码常用的几招,高效程序的秘密_hacker's delight读书笔记
- iOS-MVVM设计模式
- JDK的动态代理-面向切面编程简单使用
- 欢迎使用CSDN-markdown编辑器
- 2015.10去哪儿校招面试面经-研发工程师
- 【软件项目管理】作业一:a project I finished
- 兼容ie6及以上的表格行滑过时背景色切换的效果
- 设置cookie值(key,value,过期天数,域名)functionsetCookie(cookieName, cookieValue, expire
- 算法:递归
- eclipse 导入其他人的项目时tomcat出现Hibernate错误
- 如何用 Retrofit 2 在安卓上实现 HTTP 访问?
- Oracle EBS R12 WIP Component Issue&Return Process
- 三种数据库的分页
- hadoop的应用场景分析
- C语言实现非循环双链表节点的删除(不带头结点)
- Masonry介绍与使用实践(快速上手Autolayout)
- Python Mako
- 自我介绍
- Fiddler+Jmeter+断言详细教程