• [bzoj2044] 三维导弹拦截 (二分图最大匹配+dp)


    传送门

    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

    Solution

    第一问对a排序后(n^2)暴力dp
    第二问我们先把能转移的地方连边,求最大边覆盖 (n-最大匹配)

    Code

    //By Menteur_Hxy
    #include <cstdio>
    #include <cstring>
    #include <cstdlib>
    #include <iostream>
    #include <algorithm>
    #define F(i,a,b) for(register int i=(a);i<=(b);i++)
    #define E(i,u) for(register int i=head[u],v;i;i=nxt[i])
    #define add(a,b) nxt[++cnt]=head[a],to[cnt]=b,head[a]=cnt
    using namespace std;
    
    int read() {
    	int x=0,f=1; char c=getchar();
    	while(!isdigit(c)) {if(c=='-')f=-f;c=getchar();}
    	while(isdigit(c)) x=(x<<1)+(x<<3)+c-48,c=getchar();
    	return x*f;
    }
    
    const int N=1010;
    bool vis[N];
    int n,cnt,ans1,ans2;
    int nxt[N*N],to[N*N],head[N];
    int f[N],fr[N];
    struct GM{
    	int a,b,c;
    	bool operator <(const GM oth) const{return a<oth.a;}
    }g[N];
    
    bool dfs(int x) {
    	E(i,x) if(!vis[(v=to[i])]) {
    		vis[v]=1;
    		if(!fr[v]||dfs(fr[v])) {fr[v]=x;return 1;}
    	}
    	return 0;
    }
    
    int main() {
    	n=read();
    	F(i,1,n) {
    		int x=read(),y=read(),z=read();
    		g[i]=(GM){x,y,z};
    	}
    	sort(g+1,g+1+n);
    	F(i,1,n) {
    		f[i]=1;
    		F(j,1,i-1) if(g[j].a<g[i].a&&g[j].b<g[i].b&&g[j].c<g[i].c) 
    			f[i]=max(f[i],f[j]+1),add(j,i);
    		ans1=max(ans1,f[i]);
    	}
    	F(i,1,n) {
    		memset(vis,0,sizeof(vis));
    		if(dfs(i)) ans2++;
    	}
    	printf("%d
    %d
    ",ans1,n-ans2);
    	return 0;
    }
    
    版权声明:本文为博主原创文章,未经博主允许不得转载。 博主:https://www.cnblogs.com/Menteur-Hxy/
  • 相关阅读:
    数据库路由中间件MyCat
    MyCat
    网页动画师与技术开发,如何精准高效的协作完成动效。
    JAVA异常的最佳工程学实践探索
    MySQL导入.sql文件及常用命令
    如何申请新浪SAE,发布自己的网站
    新手教程: 如何在新浪云计算SAE里部署代码
    微信公众平台开发(一) 配置接口
    SQL数据库面试题以及答案
    Sql Server之旅——终点站 nolock引发的三级事件的一些思考
  • 原文地址:https://www.cnblogs.com/Menteur-Hxy/p/9489306.html
Copyright © 2020-2023  润新知