Solution

第一问很明显,是动态规划

先把每个导弹排序后,f[i]表示拦截最后一颗导弹为i的最大拦截数

f[i]=max(f[i],f[j]+1)

那么对于第二问,就要换个思路

我们可以想,在系统拦截一个导弹i后,再拦截一个导弹j,点i向j连一条有向边

这样就形成了有向无环图(DAG)

所以问题转化成了求有向图的最小覆盖

有多少条不相交的边可以覆盖整张图)

可以把原来的一个点拆成两个点(一个为入点,一个为出点)

总共分别有n个入点和n个出点形成了二分图

所以我们只需要把二分图的最大匹配ans求出来,最后把n-ans即是答案

这里我选择了匈牙利算法(其他做法也许可以),机子跑得快

要注意最好用位运算符,速度快,不然有可能过不了,我试过了

代码如下:

//blog:https://www.cnblogs.com/yjyl0098/
#include<bits/stdc++.h>
using namespace std;
#define maxn 1000+50
int ans;
int q[maxn<<1][maxn];
int f[maxn<<1];
bool judge[maxn<<1];
struct yjyl
{
    int x,y,z;
}a[maxn];

inline bool cmp(yjyl x,yjyl y)
{
    return x.x<y.x;
}
inline int read()
{
    int X=0,w=1;
    char ch=0;
    while(ch<'0' || ch>'9') {if(ch=='-') w=-1;ch=getchar();}
    while(ch>='0' && ch<='9') X=(X<<3)+(X<<1)+ch-'0',ch=getchar();
    return X*w;
}
inline int max(int x,int y)
{
    return x>y?x:y;
}
inline int  Hg(int x)
{
    for(int i=1;i<=q[x][0];i++)
        if(!judge[q[x][i]])
        {
            judge[q[x][i]]=1;
            if(!f[q[x][i]]||Hg(f[q[x][i]]))
            {
                f[q[x][i]]=x;
                return 1;
            }
        }
    return 0;
}//把一个点拆成两个点,跑匈牙利算法
int main()
{
    freopen("missile.in","r",stdin);
    freopen("missile.out","w",stdout);
    int n=read();
    for(int i=1;i<=n;i++) a[i].x=read(),a[i].y=read(),a[i].z=read();
    sort(a+1,a+n+1,cmp);
    for(int i=1;i<=n;i++)
        for(int j=f[i]=1;j<i;j++)
            if(a[i].y>a[j].y&&a[i].z>a[j].z)
            {
                f[i]=max(f[i],f[j]+1);//动态规划
                q[j<<1][++q[j<<1][0]]=i<<1|1;
            }
    for(int i=1;i<=n;i++)
    {
        if(f[i]>ans) ans=f[i];
        f[i]=0;
    }
    printf("%d\n",ans),ans=0;
    for(int i=2;i<=n<<1;i+=2)
    {
        memset(judge,0,sizeof(judge));
        if(Hg(i)!=0) ans++;//ans求的就是最大匹配数
    }
    printf("%d",n-ans);//为什么是减呢?因为多一个匹配就少一个系统
}

end