【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). 最小割: 割是网 ...
随机推荐
- Python 正则表达式_re模块_使用compile加速
使用compile加速 compile( rule [,flag] ) 将正则规则编译成一个Pattern对象,以供接下来使用. 第一个参数是规则式,第二个参数是规则选项. 返回一个Pattern对象 ...
- 【GoLang】GO语言系列--001.GO开发环境搭建
- 《ASP.NET MVC4 WEB编程》学习笔记------.net mvc实现原理ActionResult/View
ActionResult ActionResult是Action的返回结果.ActionResult 有多个派生类,每个子类功能均不同,并不是所有的子类都需要返回视图View,有些直接返回流,有些返回 ...
- Nested List Weight Sum I & II
Nested List Weight Sum I Given a nested list of integers, return the sum of all integers in the list ...
- #ifdef 的技巧用法
-- int _tmain(int argc, _TCHAR* argv[]) { #ifdef DEBUG cout<<"DEBUG has been defined" ...
- hdu3555
基本的数位dp #include <cstdio> #include <cstring> using namespace std; #define D(x) x ; long ...
- Android之canvas详解
首先说一下canvas类: Class Overview The Canvas class holds the "draw" calls. To draw something, y ...
- ***mysql中经度纬度字段用什么存储(关于mysql的float和decimal区别)
float,decimal精确度比较 float,double容易产生误差,对精确度要求比较高时,建议使用decimal来存,decimal在mysql内存是以字符串存储的, 用于定义货币要求精确 ...
- iOS开发网络篇—GET请求和POST请求(转)
一.GET请求和POST请求简单说明 创建GET请求 1 // 1.设置请求路径 2 NSString *urlStr=[NSString stringWithFormat:@"http:/ ...
- vijos 1038 括号+路径 ***
链接:点我 就是自己写不出来 #include <cstdio> #include <climits> #include <memory.h> using name ...