[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\n%d\n",ans1,n-ans2);
	return 0;
}
posted @ 2018-08-16 19:13  Menteur_hxy  阅读(274)  评论(0编辑  收藏  举报