codevs1409 拦截导弹2

Posted ljh2000

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了codevs1409 拦截导弹2相关的知识,希望对你有一定的参考价值。

【问题描述】
一场战争正在 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\n1"); 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\n",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 }

 

以上是关于codevs1409 拦截导弹2的主要内容,如果未能解决你的问题,请参考以下文章

codevs1409 拦截导弹2

codevs 1128 导弹拦截 (贪心)

codevs1044 拦截导弹==洛谷 P1020 导弹拦截

Codevs 1044 拦截导弹

codevs1128 导弹拦截

codevs 1128 导弹拦截