[最小路径覆盖]拦截导弹

题目描述

某国为了防御敌国的导弹袭击,发展出一种导弹拦截系统。但是这种导弹拦截系统有一个缺陷:虽然它的第一发炮弹能够到达任意的高度,但是以后每一发炮弹都不能高于前一发的高度。某天,雷达捕捉到敌国的导弹来袭。由于该系统还在试用阶段,所以只有一套系统,因此有可能不能拦截所有的导弹。

输入输出格式

输入格式

输入导弹依次飞来的高度(雷达给出的高度数据是不大于30000的正整数)

输出格式

计算这套系统最多能拦截多少导弹,如果要拦截所有导弹最少要配备多少套这种导弹拦截系统。

输入输出样例

输入样例#1:

300 250 275 252 200 138 245

输出样例#1:

5
2

题目解析

对于第一问,跑一遍dp就行了
第二问是问你至少配备几套系统可以拦截所有导弹,也就是用足够多的路径去覆盖这张图,那就转换成了最小路径覆盖问题

代码

#include<iostream>
#include<vector>
#include<cstring>
#include<cstdio>
using namespace std;
int a[30005],ai,link[30005],ans,f[30005],ans1;
vector<int> v[30005];
bool flag[30005];
bool find(int x)
{
	for(int i=0;i<v[x].size();i++)
	 if(!flag[v[x][i]])
	 {
	 	int j=v[x][i];
	 	flag[j]=1;
	 	int q=link[j];
	 	link[j]=x;
	 	if(!q||find(q)) return true;
	 	link[j]=q;
	 }
	return false;
}//最大匹配
int main()
{
	while(scanf("%d",&a[++ai])!=EOF);//输入
	ai--;
	f[0]=1e8;
	for(int i=1;i<=ai;i++)
	 if(f[ans1]>=a[i])
	  f[++ans1]=a[i];
	 else
      {
        int l=1,r=ans1;
        while(l<=r)
        {
            int mid=(l+r)/2;
            if(f[mid]>=a[i]) l=mid+1;else r=mid-1;
        }
        f[l]=a[i];
      }//DP
    cout<<ans1<<endl;
	for(int i=1;i<=ai;i++)
	 for(int j=i+1;j<=ai;j++)
	  if(a[i]>=a[j])
	   v[i].push_back(j);//连边
	for(int i=1;i<=ai;i++)
	{
	  memset(flag,0,sizeof(flag));
	  ans+=find(i);
	}
	cout<<ai-ans;//最小路径覆盖数=顶点数-最大匹配数
}

猜你喜欢

转载自blog.csdn.net/weixin_43909855/article/details/85108727