题目描述
某国为了防御敌国的导弹袭击,发展出一种导弹拦截系统。但是这种导弹拦截系统有一个缺陷:虽然它的第一发炮弹能够到达任意的高度,但是以后每一发炮弹都不能高于前一发的高度。某天,雷达捕捉到敌国的导弹来袭。由于该系统还在试用阶段,所以只有一套系统,因此有可能不能拦截所有的导弹。
输入输出格式
输入格式
输入导弹依次飞来的高度(雷达给出的高度数据是不大于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;//最小路径覆盖数=顶点数-最大匹配数
}