jzoj5354. 导弹拦截

版权声明:本人初三蒟蒻一只,欢迎各位大佬来点评。 https://blog.csdn.net/HiChocolate/article/details/85387145

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.

猜你喜欢

转载自blog.csdn.net/HiChocolate/article/details/85387145