zoukankan      html  css  js  c++  java
  • jzoj5354. 导弹拦截

    Description

    某国为了防御敌国的导弹袭击,发展出一种导弹拦截系统。
    敌国的导弹形成了立体打击,每个导弹可以抽象成一个三维空间中的点(x; y; z)。拦截系统发射的炮弹也很好地应对了这种情况,每一发炮弹也可以视为一个三维空间中的点。
    但是这种导弹拦截系统有一个缺陷:虽然它的第一发炮弹能够到达三维空间中任意的点,但是以后每一发炮弹到达点的坐标(x; y; z) 的三个坐标值都必须大于前一发炮弹的对应坐标值。
    某天,雷达捕捉到敌国的导弹来袭。由于该系统还在试用阶段,所以只有一套系统,因此有可能不能拦截所有的导弹。
    输入导弹飞来的坐标,计算这套系统最多能拦截多少导弹,如果要拦截所有导弹最少要配备多少套这种导弹拦截系统。注意: 所有导弹都是同时飞来的。

    Input

    第一行一个正整数n,表示敌国导弹数目。
    接下来n 行,每行三个非负整数xi,yi,zi,表示一个敌国导弹的三维坐标。
    数据保证所有的导弹坐标互不相同。

    Output

    第一行一个整数,表示一套系统最多拦截的导弹数。
    第二行一个整数,表示拦截所有导弹最少配备的系统数。

    Sample Input

    4
    0 0 0
    1 1 0
    1 1 1
    2 2 2

    Sample Output

    3
    2

    Data Constraint

    对于30% 的数据,n <=10
    对于100% 的数据,n <= 1000,x; y; z <= 10^6

    题解

    这题是道好题。
    首先,我们考虑第一问的答案,我们发现,就是一个最长上升子序列。
    这样就完美地求出第一问的答案。
    其次,我们考虑第二问的答案。
    别人说这个很显然以前做过,用二分图匹配。
    但我怎么就没印象?还打了个暴力,还得了个30分。
    好吧,原来我是打贪心的,不行。
    怎么办?我们考虑建图——
    当第i颗导弹拦截完之后,还能拦截第j颗导弹,则从i连一条到j的边。
    于是乎,这题就转化成了一个求有向无环图的最小路径覆盖。
    所以就用匈牙利即可。
    这里有道板题:jzoj1156. 【GDKOI2004】使命的召唤
    不会的话可以自己学学。

    程序

    {$inline on}
    uses math;
    var
            i,j,k,l,n,m,ans1,ans2:longint;
            x,y,z:array[0..1001] of longint;
            f,g:array[0..1001] of longint;
            next,last:array[0..1001] of longint;
            flag:array[0..1001] of boolean;
            edgs:array[1..1000,0..1000] of longint;
            b,c:array[1..2000] of longint;
            bz:boolean;
    function can(x:longint):boolean;
    var
            ii:longint;
    begin
            if c[x]=i then exit(false);
            c[x]:=i;
            for ii:=1 to edgs[x,0] do
            begin
                    if (b[edgs[x,ii]]=0)or (can(b[edgs[x,ii]]))then
                    begin
                            b[edgs[x,ii]]:=x;
                            exit(true);
                    end;
            end;
            exit(false);
    end;
    procedure swap(var x,y:longint);inline;
    var
            z:longint;
    begin
            z:=x;x:=y;y:=z;
    end;
    procedure qsort(l,r:longint);
    var
            i,j,m1,m2,m3:longint;
    begin
            i:=l;j:=r;
            m1:=x[(l+r) div 2];
            m2:=y[(l+r) div 2];
            m3:=z[(l+r) div 2];
            repeat
                    while (x[i]<m1) or ((x[i]=m1) and (y[i]<m2)) or ((x[i]=m1) and (y[i]=m2) and (z[i]<m3)) do inc(i);
                    while (x[j]>m1) or ((x[j]=m1) and (y[j]>m2)) or ((x[j]=m1) and (y[j]=m2) and (z[j]>m3)) do dec(j);
                    if i<=j then
                    begin
                            swap(x[i],x[j]);
                            swap(y[i],y[j]);
                            swap(z[i],z[j]);
                            inc(i);dec(j);
                    end;
            until i>j;
            if l<j then qsort(l,j);
            if r>i then qsort(i,r);
    end;
    begin
            assign(input,'missile.in');reset(input);
            assign(output,'missile.out');rewrite(output);
            readln(n);
            for i:=1 to n do
            begin
                    readln(x[i],y[i],z[i]);
            end;
            qsort(1,n);
    
            for i:=1 to n+1 do
            begin
                    next[i-1]:=i;
                    last[i]:=i-1;
            end;
            fillchar(flag,sizeof(flag),true);
            m:=n;
            while m>0 do
            begin
                    x[0]:=-maxlongint;
                    y[0]:=-maxlongint;
                    z[0]:=-maxlongint;
                    fillchar(f,sizeof(f),0);
                    flag[0]:=true;
                    i:=1;
                    for i:=1 to n do if flag[i] then break;
                    while i<=n do
                    begin
                            for j:=0 to i-1 do
                            begin
                                    if flag[j] then
                                    begin
                                            if (x[i]>x[j]) and (y[i]>y[j]) and (z[i]>z[j]) then
                                            begin
                                                    if f[j]+1>f[i] then
                                                    begin
                                                            f[i]:=f[j]+1;
                                                            g[i]:=j;
                                                    end;
                                            end;
                                    end;
                            end;
                            i:=next[i];
                    end;
                    ans1:=0;
                    j:=0;
                    for i:=1 to n do
                    begin
                            if f[i]>ans1 then
                            begin
                                    ans1:=f[i];
                                    j:=i;
                            end;
                    end;
                    if not bz then
                    begin
                            writeln(ans1);
                            bz:=true;
                            break;
                    end;
            end;
            for i:=1 to n do
            begin
                    for j:=1 to n do
                    begin
                            if i<>j then
                            begin
                                    if (x[i]<x[j]) and (y[i]<y[j]) and (z[i]<z[j]) then
                                    begin
                                            inc(edgs[i,0]);
                                            edgs[i,edgs[i,0]]:=j+n;
                                    end;
                            end;
                    end;
            end;
            fillchar(flag,sizeof(flag),false);
            ans2:=n;
            for i:=1 to n do
            begin
                    if edgs[i,0]>0 then
                    begin
                            if can(i) then dec(ans2);
                    end;
            end;
            writeln(ans2);
    end.
    
    我活在这夜里。无论周围多么黑暗,我都要努力发光!我相信着,终有一天,我会在这深邃的夜里,造就一道最美的彩虹。
  • 相关阅读:
    20170809--JS操作Select备忘
    20160711--C# 委托的三种调用示例(同步调用 异步调用 异步回调)【转载】
    C# 内存建表备忘
    富文本编辑器 CKeditor 配置使用
    20160520—JS打分控件
    20160513--js 弹出窗口带有iframe控件 备忘
    chart 简单应用
    mvc 简单整理
    ObjectDatasourse 的绑定及显示
    GridView 详述
  • 原文地址:https://www.cnblogs.com/RainbowCrown/p/11148375.html
Copyright © 2011-2022 走看看