【BZOJ】1458: 士兵占领(上下界网络流)
http://www.lydsy.com/JudgeOnline/problem.php?id=1458
是不是我脑洞太小了。。。。。。。直接弄上下界最小流。。。。。。。。(就当复习了。。
二分图X和Y,然后如果(x,y)能放,那么连边x->y,上界1,下界0。
然后源s->x连下界为要求的下界,上界为oo
y->t连下界为要求下界,上界为oo。
然后来一次上下界最小流。。
//看了题解。。。感觉。。。。。。。。我脑洞怎么那么小。。。。将问题转换为:放满棋盘后去掉最多的士兵。搬运hzwer学长的题解:
此题的思路是先放满棋盘,然后考虑最多可以删多少个。。。
某一行和某一列的可以放的格子数小于需求就直接jiong掉
然后从源向每一行连边,流量为可以放的格子数 - 需求的格子数(也就是可以删多少格子)
从每一列向汇,同上.
从每一个非障碍的格子的行向列连边流量为1
跑一遍最大流即可ans=可放格子数-maxflow
囧。。
#include <cstdio>
#include <cstring>
#include <cmath>
#include <string>
#include <iostream>
#include <algorithm>
#include <queue>
#include <set>
#include <map>
using namespace std;
typedef long long ll;
#define rep(i, n) for(int i=0; i<(n); ++i)
#define for1(i,a,n) for(int i=(a);i<=(n);++i)
#define for2(i,a,n) for(int i=(a);i<(n);++i)
#define for3(i,a,n) for(int i=(a);i>=(n);--i)
#define for4(i,a,n) for(int i=(a);i>(n);--i)
#define CC(i,a) memset(i,a,sizeof(i))
#define read(a) a=getint()
#define print(a) printf("%d", a)
#define dbg(x) cout << (#x) << " = " << (x) << endl
#define error(x) (!(x)?puts("error"):0)
#define rdm(x, i) for(int i=ihead[x]; i; i=e[i].next)
inline const int getint() { int r=0, k=1; char c=getchar(); for(; c<'0'||c>'9'; c=getchar()) if(c=='-') k=-1; for(; c>='0'&&c<='9'; c=getchar()) r=r*10+c-'0'; return k*r; } const int N=305, oo=~0u>>1;
int ihead[N], cnt=1;
struct dat { int next, to, from, cap; }e[N*N*2];
void add(int u, int v, int c) {
e[++cnt].next=ihead[u]; ihead[u]=cnt; e[cnt].from=u; e[cnt].to=v; e[cnt].cap=c;
e[++cnt].next=ihead[v]; ihead[v]=cnt; e[cnt].from=v; e[cnt].to=u; e[cnt].cap=0;
}
int p[N], d[N], gap[N], cur[N];
int isap(int s, int t, int n) {
for1(i, 0, n) p[i]=0, d[i]=0, gap[i]=0, cur[i]=ihead[i];
gap[0]=n; int ret=0, f, u=s, i;
while(d[s]<n) {
for(i=cur[u]; i; i=e[i].next) if(e[i].cap && d[e[i].to]+1==d[u]) break;
if(i) {
p[e[i].to]=cur[u]=i; u=e[i].to;
if(u==t) {
for(f=oo; u!=s; u=e[p[u]].from) f=min(f, e[p[u]].cap);
for(u=t; u!=s; u=e[p[u]].from) e[p[u]].cap-=f, e[p[u]^1].cap+=f;
ret+=f;
}
}
else {
if(!(--gap[d[u]])) break;
d[u]=n; cur[u]=ihead[u];
for(i=ihead[u]; i; i=e[i].next) if(e[i].cap && d[e[i].to]+1<d[u]) d[u]=d[e[i].to]+1;
++gap[d[u]];
if(u!=s) u=e[p[u]].from;
}
}
return ret;
} int n, m, k, x[N], y[N], vis[N][N], in[N];
#define X(i) (i)
#define Y(i) (n+i)
int main() {
read(n); read(m); read(k); int s=n+m+1, t=s+1;
for1(i, 1, n) read(x[i]);
for1(i, 1, m) read(y[i]);
for1(i, 1, k) { int u=getint(), v=getint(); vis[u][v]=1; }
for1(i, 1, n) for1(j, 1, m) if(!vis[i][j]) add(X(i), Y(j), 1); int S=t+1, T=S+1;
for1(i, 1, n) in[X(i)]+=x[i], in[s]-=x[i];
for1(i, 1, m) in[t]+=y[i], in[Y(i)]-=y[i];
for1(i, 0, T) if(in[i]>0) add(S, i, in[i]); else if(in[i]<0) add(i, T, -in[i]); isap(S, T, T);
add(t, s, oo);
int ans=isap(S, T, T);
rdm(S, i) if(e[i].cap) { puts("JIONG!"); return 0; }
print(ans);
return 0;
}
Description
有一个M * N的棋盘,有的格子是障碍。现在你要选择一些格子来放置一些士兵,一个格子里最多可以放置一个士兵,障碍格里不能放置士兵。我们称这些士兵占领了整个棋盘当满足第i行至少放置了Li个士兵, 第j列至少放置了Cj个士兵。现在你的任务是要求使用最少个数的士兵来占领整个棋盘。
Input
第一行两个数M, N, K分别表示棋盘的行数,列数以及障碍的个数。 第二行有M个数表示Li。 第三行有N个数表示Ci。 接下来有K行,每行两个数X, Y表示(X, Y)这个格子是障碍。
Output
输出一个数表示最少需要使用的士兵个数。如果无论放置多少个士兵都没有办法占领整个棋盘,输出”JIONG!” (不含引号)
Sample Input
1 1 1 1
0 1 0 3
1 4
2 2
3 3
4 3
Sample Output
数据范围
M, N <= 100, 0 <= K <= M * N
HINT
Source
【BZOJ】1458: 士兵占领(上下界网络流)的更多相关文章
- BZOJ 1458: 士兵占领( 网络流 )
先判无解 把整个棋盘都放上士兵, 只需求最多可以拿走多少个士兵即可.每一行看做一个点r(i), 每一列看做一个点c(i) S->r(i), c(i)->T 连边, 容量为可以拿走的最大士兵 ...
- bzoj 1458: 士兵占领 -- 最大流
1458: 士兵占领 Time Limit: 10 Sec Memory Limit: 64 MB Description 有一个M * N的棋盘,有的格子是障碍.现在你要选择一些格子来放置一些士兵 ...
- BZOJ 1458 / Luogu P4311 士兵占领 (上下界最小流 / 直接最大流)
做法1:上下界最小流 先来一发上下界最小流,思路比较暴力,就是把行和列看作n+mn+mn+m个点,(i,j)(i,j)(i,j)如果能占领就从第iii行向第jjj列连一条边,上界为1下界为0;然后从s ...
- 【刷题】BZOJ 1458 士兵占领
Description 有一个M * N的棋盘,有的格子是障碍.现在你要选择一些格子来放置一些士兵,一个格子里最多可以放置一个士兵,障碍格里不能放置士兵.我们称这些士兵占领了整个棋盘当满足第i行至少放 ...
- BZOJ 1458 士兵占领
http://www.lydsy.com/JudgeOnline/problem.php?id=1458 题意:n x m的棋盘,k个位置不能放,每行和每列都有要求至少的士兵,求能否有最少的满足条件的 ...
- bzoj 1458 士兵占领(最大流)
[题意] n行m列,第i行必须放L[i],第j列必须放C[j],有障碍格,求满足条件至少需要放多少. [思路] 至少放多少等价于最多不放多少. 对行列分别建XY点,则连边(S,Xi,a)(Yi,T,b ...
- BZOJ 2406 二分+有上下界的网络流判定
思路: 求出每行的和 sum_row 每列的和 sum_line 二分最后的答案mid S->i 流量[sum_row[i]-mid,sum_row[i]+mid] i->n+j ...
- hdu 4940 Destroy Transportation system( 无源汇上下界网络流的可行流推断 )
题意:有n个点和m条有向边构成的网络.每条边有两个花费: d:毁坏这条边的花费 b:重建一条双向边的花费 寻找这样两个点集,使得点集s到点集t满足 毁坏全部S到T的路径的费用和 > 毁坏全部T到 ...
- ACM-ICPC 2018 沈阳赛区网络预赛 F Fantastic Graph(贪心或有源汇上下界网络流)
https://nanti.jisuanke.com/t/31447 题意 一个二分图,左边N个点,右边M个点,中间K条边,问你是否可以删掉边使得所有点的度数在[L,R]之间 分析 最大流不太会.. ...
- 算法笔记--最大流和最小割 && 最小费用最大流 && 上下界网络流
最大流: 给定指定的一个有向图,其中有两个特殊的点源S(Sources)和汇T(Sinks),每条边有指定的容量(Capacity),求满足条件的从S到T的最大流(MaxFlow). 最小割: 割是网 ...
随机推荐
- System.SysUtils.TMarshaller 与 System.TMarshal
转自:http://www.cnblogs.com/del/archive/2013/06/10/3130974.html TMarshaller(结构) 基于 TMarshal(是有一大堆的 cla ...
- OpenStack 的Nova组件详解
Open Stack Compute Infrastructure (Nova) Nova是OpenStack云中的计算组织控制器.支持OpenStack云中实例(instances)生命周期的所有活 ...
- 最长回文子串O(n)算法
原文链接:英文版链接 首先,我们将字符串S中插入符号“#”转化成另一个字符串T. 比如:S = "abaaba",T = “#a#b#a#a#b#a#”. 为了找到最长回文字串,我 ...
- java面试总结-(hibernate ibatis struts2 spring)
说说Hibernate对象的三种状态 Hibernate对象有三种状态,分别是:临时态(Transient). 持久态(Persistent).游离态(Detached). 临时状态:是指从对象通过n ...
- javascript的事件监听与捕获和冒泡
在前端开发中,我们经常需要对某些事件进行监听.这样只要在指定的元素上触发了该事件,就会执行一个回调来进行相关的操作. 而js中事件监听方法总共有三种,分别如下所示: element.addEventL ...
- Android 中的异步下载
网上提到最多的就是利用AsyncTask进行异步下载,用android-async-http第三方库的也比较多.这里写点注意事项. 先说说android-async-http,这个库发送请求利用thr ...
- codeforces 489B. BerSU Ball 解题报告
题目链接:http://codeforces.com/problemset/problem/489/B 题目意思:给出 n 个 boys 的 skills 和 m 个 girls 的 skills,要 ...
- HDU 5745 La Vie en rose (DP||模拟) 2016杭电多校联合第二场
题目:传送门. 这是一道阅读理解题,正解是DP,实际上模拟就能做.pij+1 指的是 (pij)+1不是 pi(j+1),判断能否交换输出即可. #include <iostream> # ...
- [Android Pro] UI设计师不可不知的安卓屏幕知识
reference to : http://www.android100.org/html/201505/24/149342.html 不少设计师和工程师都被安卓设备纷繁的屏幕搞得晕头转向,我既做UI ...
- java中值类型和引用类型的区别
[定义] 引用类型表示你操作的数据是同一个,也就是说当你传一个参数给另一个方法时,你在另一个方法中改变这个变量的值,那么调用这个方法是传入的变量的值也将改变. 值类型表示复制一个当前变量传给方法,当你 ...