您的位置:首页 > 其它

JZOJ5354. 【NOIP2017提高A组模拟9.9】导弹拦截

2017-09-09 15:41 513 查看

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

题解

这题分为两个问题,对于第一个问,我们是可以很简单地求出答案。

我们根据能否接着发射导弹来连边。

如果两个导弹i,j,在i发射之后还可以发射j

也就是说xi<xj and yi<yj and zi<zj

就由i向j连一条有向边。

这样连边之后就一定是DAG。

对于第二问,我们先假设每个导弹都要一个系统,

那么最开始的时候就有n个系统。

如果在一个导弹发射之后,还能发射下一个导弹,那么这样就可以节省一个系统。

在它发射完以后,可以找下一个接着发射,也就是它的边连着的那些点。

但是,某些导弹可能在发射完多个导弹之后都可以发射它,那么这样就是重复。

那样就是一个二分图匹配,设这个DAG的最大匹配是m,

那么答案就是n-m。

code

#include<queue>
#include<cstdio>
#include<iostream>
#include<algorithm>
#include <cstring>
#include <string.h>
#include <cmath>
#include <math.h>
#define ll long long
#define N 2003
#define db double
#define P putchar
#define G getchar
#define mo 1000000007
using namespace std;
char ch;
void read(int &n)
{
n=0;
ch=G();
while((ch<'0' || ch>'9') && ch!='-')ch=G();
ll w=1;
if(ch=='-')w=-1,ch=G();
while('0'<=ch && ch<='9')n=n*10+ch-'0',ch=G();
n*=w;
}

int max(int a,int b){return a>b?a:b;}
int min(int a,int b){return a<b?a:b;}

void write(int x)
{
if(x>9) write(x/10);
P(x%10+'0');
}

struct node{
int x,y,z;
}a
;

int f
,n,ans,mx,x;
int d
,q
,l,r,g
;
int next[N*N],t[N*N],b
,tot;
bool bz
;

bool pd(int x,int y)
{
return a[x].x<a[y].x && a[x].y<a[y].y && a[x].z<a[y].z;
}

void ins(int x,int y)
{
next[++tot]=b[x];
t[tot]=y;
b[x]=tot;
d[y]++;
}

bool find(int x)
{
for(int i=b[x];i;i=next[i])
{
if(bz[t[i]])continue;
bz[t[i]]=1;
if(g[t[i]]==0 || find(g[t[i]]))
{
g[t[i]]=x;
return 1;
}
}
return 0;
}

int main()
{
freopen("missile.in","r",stdin);
freopen("missile.out","w",stdout);
read(n);memset(f,0,sizeof(f));
for(int i=1;i<=n;i++)
{
read(a[i].x);read(a[i].y);read(a[i].z);
}

for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
if(pd(i,j))ins(i,j);

l=r=0;
for(int i=1;i<=n;i++)
if(d[i]==0)q[++r]=i,f[i]=1;
ans=r;

while(l<r)
{
x=q[++l];
for(int i=b[x];i;i=next[i])
{
f[t[i]]=max(f[t[i]],f[x]+1),d[t[i]]--;
if(d[t[i]]==0)q[++r]=t[i];
}
mx=max(mx,f[x]);
}

write(mx),P('\n');

ans=n;
memset(bz,0,sizeof(bz));
for(int i=1;i<=n;i++)
{
memset(bz,0,sizeof(bz));
ans-=find(i);
}

write(ans);
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  二分图