【问题描述】
一场战争正在 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 国的所有导弹?
不管是为了个人荣誉还是国家容易,更多的是为了饭碗,你,都应该好好的把这个问题解决掉!
【输入文件】
第一行一个整数 N 给出 B 国导弹的数目。
接下来 N 行每行三个非负整数 Xi, Yi, Zi 给出一个导弹的位置,你可以假定任意两个导弹不会出现在同一位置。
【输出文件】
输出文件有且仅有两行。
第一行输出一个整数 P,表示一枚拦截导弹之多能够摧毁的导弹数。
第二行输出一个整数 Q,表示至少需要的拦截导弹数目。
【输入输出样例】
输入
4
0 0 0
1 1 0
1 1 1
2 2 2
输出
3
2
【数据范围】
所有的坐标都是[0,10 6 ]的整数
对于 30%的数据满足 N < 31
对于 50%的数据满足 N < 101
对于 100%的数据满足 N < 1001
正解:DP+二分图最大匹配
解题报告:
第一问直接DP,第二问考虑题目求得是一个最小路径覆盖,那么我们可以证明最小路径覆盖(最小路径数)等于总点数n-最大匹配数。因为假设都没有匹配,那么最小路径覆盖就等于n,然后每多一条边,也就意味着路径多拓展了一格,所以就可以减少一条路径,那么就可以视为路径条数-1,所以可以大概意会到最小路径覆盖(最小路径数)等于总点数n-最大匹配数,具体证明见这篇博客,写的非常清楚、详细:http://blog.csdn.net/l04205613/article/details/6278394
所以直接暴力连边,然后跑二分图最大匹配就可以了。
1 //It is made by jump~ 2 #include <iostream> 3 #include <cstdlib> 4 #include <cstring> 5 #include <cstdio> 6 #include <cmath> 7 #include <algorithm> 8 #include <ctime> 9 #include <vector> 10 #include <queue> 11 #include <map> 12 #include <set> 13 using namespace std; 14 typedef long long LL; 15 #define RG register 16 const int MAXN = 4011; 17 const int MAXM = 400011; 18 int n,ans,ecnt; 19 int f[MAXN],next[MAXM],first[MAXN],to[MAXM],vis[MAXN],match[MAXN]; 20 struct node{ 21 int x,y,z; 22 }a[MAXN]; 23 24 inline int getint() 25 { 26 RG int w=0,q=0; RG char c=getchar(); 27 while((c<'0' || c>'9') && c!='-') c=getchar(); if(c=='-') q=1,c=getchar(); 28 while (c>='0' && c<='9') w=w*10+c-'0', c=getchar(); return q ? -w : w; 29 } 30 inline bool cmp(node q,node qq){ if(q.x==qq.x && q.y==qq.y) return q.z<qq.x; if(q.x==qq.x) return q.y<qq.y; return q.x<qq.x; } 31 inline void link(RG int x,RG int y){ next[++ecnt]=first[x]; first[x]=ecnt; to[ecnt]=y; } 32 inline bool dfs(RG int x,RG int o){ 33 if(vis[x]==o) return false; vis[x]=o; 34 for(RG int i=first[x];i;i=next[i]) { 35 RG int v=to[i]; if(vis[v]==o) continue; 36 if(!match[v] || dfs(match[v],o)) { 37 match[v]=x; match[x]=v; 38 return true; 39 } 40 } 41 return false; 42 } 43 44 inline void work(){ 45 n=getint(); for(RG int i=1;i<=n;i++) a[i].x=getint(),a[i].y=getint(),a[i].z=getint(),f[i]=1; 46 ans=1; if(n==1) { printf("1 1"); return ; } 47 sort(a+1,a+n+1,cmp); 48 for(RG int i=2;i<=n;i++) for(RG int j=1;j<i;j++) if(a[j].x<a[i].x && a[j].y<a[i].y && a[j].z<a[i].z) if(f[j]+1>f[i]) f[i]=f[j]+1; 49 for(RG int i=1;i<=n;i++) ans=max(ans,f[i]); 50 printf("%d ",ans); 51 for(RG int i=2;i<=n;i++) for(RG int j=1;j<i;j++) if(a[j].x<a[i].x && a[j].y<a[i].y && a[j].z<a[i].z) link(j,i+n); 52 ans=0; for(RG int i=1;i<=n;i++) if(dfs(i,i)) ans++; 53 printf("%d",n-ans); 54 } 55 56 int main() 57 { 58 work(); 59 return 0; 60 }