bzoj1458 士兵占据

1458: 士兵占据

Time Limit: 10 Sec  Memory Limit: 64 MB

Submit: 685  Solved: 398

[Submit][Status][

id=1458" style="color:blue; text-decoration:none">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 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

HINT

Source

有源汇有上下界最小流问题

将行抽象为左部点,列抽象为右部点。

假设某个位置没有障碍。就从行相应的节点到列相应的节点连边。下界为0,上界为1。

在从源点向每行相应的节点连边,从每列相应的节点向汇点连边,下界均为该行或列的最少士兵数。上界均为正无穷。

最后求s到t的最小流。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<cstdlib>
#include<algorithm>
#include<queue>
#define F(i,j,n) for(int i=j;i<=n;i++)
#define D(i,j,n) for(int i=j;i>=n;i--)
#define ll long long
#define pa pair<int,int>
#define maxn 300
#define maxm 100000
#define inf 1000000000
using namespace std;
int head[maxn],cur[maxn],dis[maxn],in[maxn];
int cnt=1,mx=0,maxflow,n,m,k,x,y,s,t,ss,tt;
bool a[105][105];
struct edge_type
{
	int next,to,v;
}e[maxm];
inline int read()
{
	int x=0,f=1;char ch=getchar();
	while (ch<'0'||ch>'9'){if (ch=='-') f=-1;ch=getchar();}
	while (ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
	return x*f;
}
inline void add_edge(int x,int y,int v)
{
	e[++cnt]=(edge_type){head[x],y,v};head[x]=cnt;
	e[++cnt]=(edge_type){head[y],x,0};head[y]=cnt;
}
inline void insert(int x,int y,int l,int r)
{
	in[x]-=l;in[y]+=l;
	if (r-l) add_edge(x,y,r-l);
}
inline void build()
{
	F(i,1,tt)
	{
		if (in[i]>0) add_edge(ss,i,in[i]);
		else if (in[i]<0) add_edge(i,tt,-in[i]);
	}
}
inline bool bfs()
{
	queue<int>q;
	memset(dis,-1,sizeof(dis));
	dis[s]=0;q.push(s);
	while (!q.empty())
	{
		int tmp=q.front();q.pop();
		if (tmp==t) return true;
		for(int i=head[tmp];i;i=e[i].next) if (e[i].v&&dis[e[i].to]==-1)
		{
			dis[e[i].to]=dis[tmp]+1;
			q.push(e[i].to);
		}
	}
	return false;
}
inline int dfs(int x,int f)
{
	if (x==t) return f;
	int tmp,sum=0;
	for(int &i=cur[x];i;i=e[i].next)
	{
		int y=e[i].to;
		if (e[i].v&&dis[y]==dis[x]+1)
		{
			tmp=dfs(y,min(f-sum,e[i].v));
			e[i].v-=tmp;e[i^1].v+=tmp;sum+=tmp;
			if (sum==f) return sum;
		}
	}
	if (!sum) dis[x]=-1;
	return sum;
}
inline void dinic()
{
	maxflow=0;
	while (bfs())
	{
		F(i,1,tt) cur[i]=head[i];
		maxflow+=dfs(s,inf);
	}
}
inline void minflow()
{
	s=ss;t=tt;
	dinic();
	int ans=e[cnt].v;
	if (ans<mx)
	{
		printf("JIONG!\n");
		return;
	}
	e[cnt].v=e[cnt^1].v=0;
	s=n+m+2;t=n+m+1;
	dinic();
	printf("%d\n",ans-maxflow);
}
int main()
{
	int tot=0;
	m=read();n=read();k=read();
	s=m+n+1;t=s+1;ss=t+1;tt=ss+1;
	F(i,1,m){x=read();tot+=x;insert(s,i,x,inf);}
	mx=max(mx,tot);
	tot=0;
	F(i,1,n){x=read();tot+=x;insert(i+m,t,x,inf);}
	mx=max(mx,tot);
	F(i,1,k)
	{
		x=read();y=read();
		a[x][y]=true;
	}
	F(i,1,m) F(j,1,n) if (!a[i][j]) insert(i,j+m,0,1);
	build();
	add_edge(t,s,inf);
	minflow();
}
时间: 2024-10-21 19:50:38

bzoj1458 士兵占据的相关文章

bzoj1458: 士兵占领

逆向思维:最少多少士兵=最多放多少空格.于是跑最大流就OK了.取行列为节点. #include<cstdio> #include<cstring> #include<iostream> #include<cmath> #include<algorithm> using namespace std; #define rep(i,n) for(int i=1;i<=n;i++) #define clr(x,c) memset(x,c,sizeo

bzoj1458: 士兵占领 网络流

链接 https://www.lydsy.com/JudgeOnline/problem.php?id=1458 也可以去luogu 思路 想成倒着删去点,使得依旧满足覆盖!! 左边横,右边列,之间用点链接起来,流量1 S到i为之间总公共 最多去掉m-h[i]-L[i]个,i到T同理. 代码 #include <iostream> #include <queue> #include <cstdio> #include <cstring> const int

【bzoj1458】士兵占领

Description 有一个M * N的棋盘,有的格子是障碍.现在你要选择一些格子来放置一些士兵,一个格子里最多可以放置一个士兵,障碍格里不能放置士兵.我们称这些士兵占领了整个棋盘当满足第i行至少放置了Li个士兵, 第j列至少放置了Cj个士兵.现在你的任务是要求使用最少个数的士兵来占领整个棋盘. Input 第一行两个数M, N, K分别表示棋盘的行数,列数以及障碍的个数. 第二行有M个数表示Li. 第三行有N个数表示Ci. 接下来有K行,每行两个数X, Y表示(X, Y)这个格子是障碍. O

【BZOJ-1458】士兵占领 最大流

1458: 士兵占领 Time Limit: 10 Sec  Memory Limit: 64 MBSubmit: 782  Solved: 456[Submit][Status][Discuss] Description 有一个M * N的棋盘,有的格子是障碍.现在你要选择一些格子来放置一些士兵,一个格子里最多可以放置一个士兵,障碍格里不能放置士兵.我们称这些士兵占领了整个棋盘当满足第i行至少放置了Li个士兵, 第j列至少放置了Cj个士兵.现在你的任务是要求使用最少个数的士兵来占领整个棋盘.

【BZOJ1458】士兵占领 最大流的模板题

我们只要把他们可以有的限制用流量限制,再用两者关系限制一下就可以开心的跑了. #include <cstdio> #include <cstring> #include <iostream> #define r register #define N 1005 using namespace std; inline int read() { r int sum=0; r char ch=getchar(); while(ch<'0'||ch>'9')ch=ge

【内存优化】加载一张图像资源到底占据多少内存

0.内容概览 1. 简介 2. 问题 3. 概念描述 4. 具体分析 5. 总结 6. 参考文档 1.简介 Android中经常要通过ImageView进行图片资源显示.在加载图片时,首先要考虑的两个因素就是体验问题和性能问题. 其中,体验问题是指图片显示的是否正确(例如Universal-Image-Loader在适配Adapter图片资源时会导致图片显示错位),分辨率是否合适等.而体验问题主要是指图片加载速度,以及更加重要的图片加载的内存占用问题.本文重点介绍ImageView加载图片中的内

NYOJ116 士兵杀敌(二)【树状数组】

士兵杀敌(二) 时间限制:1000 ms  |  内存限制:65535 KB 难度:5 描述 南将军手下有N个士兵,分别编号1到N,这些士兵的杀敌数都是已知的. 小工是南将军手下的军师,南将军经常想知道第m号到第n号士兵的总杀敌数,请你帮助小工来回答南将军吧. 南将军的某次询问之后士兵i可能又杀敌q人,之后南将军再询问的时候,需要考虑到新增的杀敌数. 输入 只有一组测试数据 第一行是两个整数N,M,其中N表示士兵的个数(1<N<1000000),M表示指令的条数.(1<M<1000

士兵站队问题 【问题描述】

9.士兵站队问题 [问题描述] 在一个划分成网格的操场上,n个士兵散乱地站在网格点上.网格点由整数坐标(x,y)表示.士兵们可以沿网格边上.下.左.右移动一步,但在同一时刻任一网格点上只能有一名士兵.按照军官的命令,士兵们要整齐地列成一个水平队列,即排列成(x,y),(x+1,y),-,(x+n-1,y).如何选择x 和y的值才能使士兵们以最少的总移动步数排成一列. [编程任务] 计算使所有士兵排成一行需要的最少移动步数. [输入格式] 由文件sol.in提供输入数据.文件的第1 行是士兵数n,

士兵杀敌(三)简单线段树

题目描述 南将军统率着N个士兵,士兵分别编号为1~N,南将军经常爱拿某一段编号内杀敌数最高的人与杀敌数最低的人进行比较,计算出两个人的杀敌数差值,用这种方法一方面能鼓舞杀敌数高的人,另一方面也算是批评杀敌数低的人,起到了很好的效果. 所以,南将军经常问军师小工第i号士兵到第j号士兵中,杀敌数最高的人与杀敌数最低的人之间军功差值是多少. 现在,请你写一个程序,帮小工回答南将军每次的询问吧. 注意,南将军可能询问很多次. 输入 只有一组测试数据第一行是两个整数N,Q,其中N表示士兵的总数.Q表示南将