[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;
}