【BZOJ2044】三维导弹拦截 DP+(有上下界的)网络流

【BZOJ2044】三维导弹拦截

Description

一场战争正在A国与B国之间如火如荼的展开。 B国凭借其强大的经济实力开发出了无数的远程攻击导弹,B国的领导人希望,通过这些导弹直接毁灭A国的指挥部,从而取得战斗的胜利!当然,A国人民不会允许这样的事情发生,所以这个世界上还存在拦截导弹。 现在,你是一名A国负责导弹拦截的高级助理。 B国的导弹有效的形成了三维立体打击,我们可以将这些导弹的位置抽象三维中间的点(大小忽略),为了简单起见,我们只考虑一个瞬时的状态,即他们静止的状态。 拦截导弹设计非常精良,可以精准的引爆对方导弹而不需要自身损失,但是A国面临的一个技术难题是,这些导弹只懂得直线上升。精确的说,这里的直线上升指xyz三维坐标单调上升。 给所有的B国导弹按照1至N标号,一枚拦截导弹可以打击的对象可以用一个xyz严格单调上升的序列来表示,例如: B国导弹位置:(0, 0, 0) (1, 1, 0) (1, 1, 1), (2, 2, 2) 一个合法的打击序列为:{1, 3, 4} 一个不合法的打击序列为{1, 2, 4} A国领导人将一份导弹位置的清单交给你,并且向你提出了两个最简单不过的问题(假装它最简单吧): 1.一枚拦截导弹最多可以摧毁多少B国的导弹? 2.最少使用多少拦截导弹才能摧毁B国的所有导弹? 不管是为了个人荣誉还是国家容易,更多的是为了饭碗,你,都应该好好的把这个问题解决掉!

Input

第一行一个整数N给出B国导弹的数目。 接下来N行每行三个非负整数Xi, Yi, Zi给出一个导弹的位置,你可以假定任意两个导弹不会出现在同一位置。

Output

第一行输出一个整数P,表示一枚拦截导弹之多能够摧毁的导弹数。 第二行输出一个整数Q,表示至少需要的拦截导弹数目。

Sample Input

4
0 0 0
1 1 0
1 1 1
2 2 2

Sample Output

3
2

HINT

所有的坐标都是[0,10^6]的整数 
对于30%的数据满足N < 31 
对于50%的数据满足N < 101 
对于100%的数据满足N < 1001

题解:第一问暴力DP即可,下面考虑第二问。

这题本质上是求最小路径覆盖,所以可以用有上下界的网络流(最小流)解决。这里不说如何建最小流了。不过,由于本题的特殊性质,最小流的第一次dinic一定是满流的,所以我们可以直接进行第二次dinic。第二次的建图方法如下:

1.S -> i 容量1
2.i‘ -> T 容量1
3.i‘ -> i 容量1
4.对于边<i,j> i-> j‘ 容量1
n-最大流即是答案。

#include <cstdio>
#include <cstring>
#include <iostream>
#include <queue>
#include <algorithm>
using namespace std;
int n,ans1,ans2,cnt,S,T;
struct node
{
	int x,y,z;
}p[1010];
int f[1010],to[2000010],next[2000010],val[2000010],head[2010],d[2010];
queue<int> q;
bool cmp(const node &a,const node &b)
{
	return a.x<b.x;
}
int dfs(int x,int mf)
{
	if(x==T)	return mf;
	int i,k,temp=mf;
	for(i=head[x];i!=-1;i=next[i])
	{
		if(d[to[i]]==d[x]+1&&val[i])
		{
			k=dfs(to[i],min(temp,val[i]));
			if(!k)	d[to[i]]=0;
			val[i]-=k,val[i^1]+=k,temp-=k;
			if(!temp)	break;
		}
	}
	return mf-temp;
}
int bfs()
{
	while(!q.empty())	q.pop();
	memset(d,0,sizeof(d));
	int i,u;
	q.push(S),d[S]=1;
	while(!q.empty())
	{
		u=q.front(),q.pop();
		for(i=head[u];i!=-1;i=next[i])
		{
			if(!d[to[i]]&&val[i])
			{
				d[to[i]]=d[u]+1;
				if(to[i]==T)	return 1;
				q.push(to[i]);
			}
		}
	}
	return 0;
}
inline void add(int a,int b,int c)
{
	to[cnt]=b,val[cnt]=c,next[cnt]=head[a],head[a]=cnt++;
	to[cnt]=a,val[cnt]=0,next[cnt]=head[b],head[b]=cnt++;
}
inline int rd()
{
	int ret=0,f=1;	char gc=getchar();
	while(gc<‘0‘||gc>‘9‘)	{if(gc==‘-‘)f=-f;	gc=getchar();}
	while(gc>=‘0‘&&gc<=‘9‘)	ret=ret*10+gc-‘0‘,gc=getchar();
	return ret*f;
}
int main()
{
	n=rd(),S=0,T=2*n+1;
	int i,j;
	for(i=1;i<=n;i++)	p[i].x=rd(),p[i].y=rd(),p[i].z=rd();
	sort(p+1,p+n+1,cmp);
	memset(head,-1,sizeof(head));
	for(i=1;i<=n;i++)
	{
		f[i]=1,add(S,i,1),add(i+n,i,1),add(i+n,T,1);
		for(j=1;j<i;j++)	if(p[j].x<p[i].x&&p[j].y<p[i].y&&p[j].z<p[i].z)
			f[i]=max(f[i],f[j]+1),add(j,i+n,1);
		ans1=max(ans1,f[i]);
	}
	printf("%d\n",ans1);
	while(bfs())
		ans2+=dfs(S,1<<30);
	printf("%d",n-ans2);
	return 0;
}
时间: 2024-10-06 14:48:29

【BZOJ2044】三维导弹拦截 DP+(有上下界的)网络流的相关文章

BZOJ2044: 三维导弹拦截

2044: 三维导弹拦截 Time Limit: 10 Sec  Memory Limit: 259 MBSubmit: 175  Solved: 76[Submit][Status] Description 一场战争正在A国与B国之间如火如荼的展开. B国凭借其强大的经济实力开发出了无数的远程攻击导弹,B国的领导人希望,通过这些导弹直接毁灭A国的指挥部,从而取得战斗的胜利!当然,A国人民不会允许这样的事情发生,所以这个世界上还存在拦截导弹. 现在,你是一名A国负责导弹拦截的高级助理. B国的导

BZOJ 2406 二分+有上下界的网络流判定

思路: 求出每行的和  sum_row 每列的和   sum_line 二分最后的答案mid S->i  流量[sum_row[i]-mid,sum_row[i]+mid] i->n+j 流量[L,R] n+j->T 流量 [sum_line[i]-mid,sum_line[i]+mid] 套用有上下界的网络流 判一下就好了.. 这是道有上下界网络流的裸题 //By SiriusRen #include <queue> #include <cstdio> #inc

有上下界的网络流2-有源汇带上下界网络流ZOJ3229

ZOJ3229题目大意:一个屌丝给m个女神拍照,计划拍照n天,每一天屌丝可以和C个女神拍照,每天拍照数不能超过D张,而且给每个女神i拍照有数量限制[Li,Ri],对于每个女神n天的拍照总和不能少于Gi,如果有解求屌丝最多能拍多少张照,并求每天给对应女神拍多少张照:否则输出-1. 解题思路:        1.增设一源点st,汇点sd,st到第i天连一条上界为Di下界为0的边,每个女神到汇点连一条下界为Gi上界为正无穷的边,对于每一天,当天到第i个女孩连一条[Li,Ri]的边.        2.

有上下界的网络流1-无源汇带上下界网络流SGU194

今天开始啃网络流了.对于求解无源汇带上下界的网络流,我们可以这样建图:建图模型:         以前写的最大流默认的下界为0,而这里的下界却不为0,所以我们要进行再构造让每条边的下界为0,这样做是为了方便处理.对于每根管子有一个上界容量up和一个下界容量low,我们让这根管子的容量下界变为0,上界为up-low.可是这样做了的话流量就不守恒了,为了再次满足流量守恒,即每个节点"入流=出流",我们增设一个超级源点st和一个超级终点sd.我们开设一个数组du[]来记录每个节点的流量情况.

poj_2396 有上下界的网络流

题目大意 一个mxn的矩阵,给出矩阵中每一行的和sh[1,2...m]以及每一列的数字的和目sv[1,2...n],以及矩阵中的一些元素的范围限制,比如a[1][2] > 1, a[2][3] < 4, a[3][3] = 10等等,且要求矩阵中的每个元素值非负.求出,是否存在满足所有给出的限制条件的矩阵,若存在输出. 题目分析 这么多限制条件..开始只能想到暴力解法+剪枝.这他妈得需要多大的脑洞才能无中生有的想到网络流解法? 不过,给出网络流的想法之后发现采用网络流解法确实很合理,很简单(唯

ZOJ 2314 Reactor Cooling 带上下界的网络流

题目链接:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemId=1314 题意: 给n个点,及m根pipe,每根pipe用来流躺液体的,单向的,每时每刻每根pipe流进来的物质要等于流出去的物质,要使得m条pipe组成一个循环体,里面流躺物质. 并且满足每根pipe一定的流量限制,范围为[Li,Ri].即要满足每时刻流进来的不能超过Ri(最大流问题),同时最小不能低于Li. 求的是最大流. 很久之前就看了带上下界的网络流,一直没看懂

【网络流补全计划】Part.Ⅲ有上下界的网络流

本来心情就非常糟糕调月下毛景树把我最后一点写代码的心情调没了 放弃 开始补全网络流. 之前学了普通最大流,那么现在开始补有上下界的网络流. 在普通最大流中,网络里的每一条边都只有流量的上界即边的容量,而引入上下界网络流之后,每个边不但有一个容量,还有一个流量下界. 我们令B(u,v)表示边(u,v)的下界.于是我们可以有表达式: B(u,v)≤f(u,v)≤C(u,v) 有这个式子可以得到 0≤f(u,v)≤C(u,v)?B(u,v) 至此,我们可以将有上下界的网络流分为几种问题来对待,接下来就

SGU 194. Reactor Cooling(无源汇有上下界的网络流)

时间限制:0.5s 空间限制:6M 题意: 显然就是求一个无源汇有上下界的网络流的可行流的问题 Solution: 没什么好说的,直接判定可行流,输出就好了 code /* 无汇源有上下界的网络流 */ #include <iostream> #include <cstring> #define ms(a,b) memset(a,b,sizeof a) using namespace std; const int MAXN = 209; struct node { int u, v

ZOJ 2314 有上下界的网络流

点击打开链接 题意:给定m条边和n个节点,每条边最少的流量和最多的流量,保证每个节点的出入流量和相等,问可以形成吗,可以则输出每条边的流量 思路:一道有上下界的网络流,因为有下界,说明我们每条边必须跑大于等于下界的流量,那我们可以转化一下,将下界设为必要边,也就是我们肯定会跑的边,而且这道题是没有源点和汇点的,所以我们要加这两个点,而对于一条边,a,b,low,high,我们a->b连的流量为high-low,a->T为low,S->b为low,跑最大流,如果满流则方案成功,找边的流量输