题目大意:
题目链接:https://jzoj.net/senior/#main/show/5354
某国为了防御敌国的导弹袭击,发展出一种导弹拦截系统。
敌国的导弹形成了立体打击,每个导弹可以抽象成一个三维空间中的点(x; y; z)。拦截系统发射的炮弹也很好地应对了这种情况,每一发炮弹也可以视为一个三维空间中的点。
但是这种导弹拦截系统有一个缺陷:虽然它的第一发炮弹能够到达三维空间中任意的点,但是以后每一发炮弹到达点的坐标(x; y; z) 的三个坐标值都必须大于前一发炮弹的对应坐标值。
某天,雷达捕捉到敌国的导弹来袭。由于该系统还在试用阶段,所以只有一套系统,因此有可能不能拦截所有的导弹。
输入导弹飞来的坐标,计算这套系统最多能拦截多少导弹,如果要拦截所有导弹最少要配备多少套这种导弹拦截系统。注意: 所有导弹都是同时飞来的。
思路:
对于第一问,很明显可以意
x
,
y
,
z
x,y,z
x,y,z中任意一维为关键字排序后
O
(
n
2
)
O(n^2)
O(n2)动态规划求出。方程为
f
[
j
]
=
m
a
x
(
f
[
j
]
,
f
[
i
]
+
1
)
(
x
i
<
x
j
,
y
i
<
y
j
,
z
i
<
z
j
)
f[j]=max(f[j],f[i]+1)(x_i<x_j,y_i<y_j,z_i<z_j)
f[j]=max(f[j],f[i]+1)(xi<xj,yi<yj,zi<zj)
对于第二问,可以用网络流求。
如果
j
j
j可以从
i
i
i转移而来(
x
i
<
x
j
,
y
i
<
y
j
,
z
i
<
z
j
x_i<x_j,y_i<y_j,z_i<z_j
xi<xj,yi<yj,zi<zj),那么就从点
i
i
i向点
j
j
j连一条边。那么,这个图就是一个有向无环图。我们要求这个图中的最小点覆盖。
那么考虑拆点,把每一个点
x
x
x拆成
x
a
x_a
xa和
x
b
x_b
xb。若
j
j
j可以从
i
i
i转移而来,那么久从
i
a
i_a
ia向
i
b
i_b
ib连边。源点
S
S
S连向所有点
i
a
(
i
∈
1
∼
n
)
i_a(i\in1\sim n)
ia(i∈1∼n),汇点
T
T
T由所有点
i
b
(
i
∈
1
∼
n
)
i_b(i\in1\sim n)
ib(i∈1∼n)连过来。然后跑一边最大流,最小点覆盖即
n
−
m
a
x
f
l
o
w
n-maxflow
n−maxflow。
代码:
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <queue>
using namespace std;
const int N=1010;
const int Inf=2e9;
int n,tot=1,ans,maxflow,S,T;
int f[N],head[N*2],cur[N*2],dep[N*2];
struct node
{
int x,y,z;
}a[N];
struct edge
{
int next,to,flow;
}e[N*N];
bool cmp(node x,node y)
{
return x.z<y.z;
}
void add(int from,int to,int flow)
{
e[++tot].to=to;
e[tot].flow=flow;
e[tot].next=head[from];
head[from]=tot;
}
bool bfs() //分层
{
memset(dep,0x3f3f3f3f,sizeof(dep));
memcpy(cur,head,sizeof(cur)); //当前弧优化
dep[S]=0;
queue<int> q;
q.push(S);
while (q.size())
{
int u=q.front();
q.pop();
for (int i=head[u];~i;i=e[i].next)
{
int v=e[i].to;
if (dep[v]>dep[u]+1&&e[i].flow)
{
dep[v]=dep[u]+1;
q.push(v);
}
}
}
return dep[T]<0x3f3f3f3f;
}
int dfs(int u,int flow)
{
int low=0;
if(u==T)
{
maxflow+=flow; //最大流
return flow;
}
int used=0;
for (int i=cur[u];~i;i=e[i].next)
{
int v=e[i].to;
cur[u]=i; //当前弧
if (e[i].flow&&dep[v]==dep[u]+1)
{
low=dfs(v,min(flow-used,e[i].flow));
if (low)
{
used+=low;
e[i].flow-=low;
e[i^1].flow+=low;
if(used==flow) break; //流满了就不能再流了
}
}
}
return used;
}
void dinic()
{
while (bfs())
dfs(S,Inf);
}
int main()
{
freopen("missile.in","r",stdin);
//freopen("missile.out","w",stdout);
memset(head,-1,sizeof(head));
scanf("%d",&n);
for (int i=1;i<=n;i++)
scanf("%d%d%d",&a[i].x,&a[i].y,&a[i].z);
sort(a+1,a+1+n,cmp);
for (int i=1;i<=n;i++)
for (int j=1;j<=n;j++)
if (a[i].x<a[j].x&&a[i].y<a[j].y&&a[i].z<a[j].z)
{
f[j]=max(f[j],f[i]+1);
ans=max(ans,f[j]);
add(i,j+n,1); //连边
add(j+n,i,0);
}
S=n*2+1;
T=n*2+2;
for (int i=1;i<=n;i++)
{
add(S,i,1);
add(i,S,0);
add(i+n,T,1);
add(T,i+n,0);
}
dinic();
printf("%d\n%d\n",ans+1,n-maxflow);
return 0;
}