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.