zoukankan      html  css  js  c++  java
  • 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
    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 }
  • 相关阅读:
    JQ轮播
    JS中正则匹配的三个方法match exec test的用法
    JavaScript 表单验证
    JS 控制CSS样式表
    AJAX 的简单用法:
    shell之运用sed将其值存到变量
    shell之创建文件及内容
    修复vbox的共享文件夹的符号链接错误
    字符转码
    php魔术方法
  • 原文地址:https://www.cnblogs.com/ljh2000-jump/p/5900969.html
Copyright © 2011-2022 走看看