zoukankan      html  css  js  c++  java
  • 【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
    ",ans1);
    	while(bfs())
    		ans2+=dfs(S,1<<30);
    	printf("%d",n-ans2);
    	return 0;
    }
  • 相关阅读:
    POJ3094 UVALive3594 HDU2734 ZOJ2812 Quicksum【进制】
    UVALive5583 UVA562 Dividing coins
    POJ1979 HDU1312 Red and Black【DFS】
    POJ1979 HDU1312 Red and Black【DFS】
    POJ2386 Lake Counting【DFS】
    POJ2386 Lake Counting【DFS】
    HDU4394 Digital Square
    HDU4394 Digital Square
    UVA213 UVALive5152 Message Decoding
    UVA213 UVALive5152 Message Decoding
  • 原文地址:https://www.cnblogs.com/CQzhangyu/p/7586468.html
Copyright © 2011-2022 走看看