洛谷Oj-导弹拦截-线性dp-最长不下降子序列

来源:互联网 发布:registax mac 编辑:程序博客网 时间:2024/05/16 19:19

问题描述
某国为了防御敌国的导弹袭击,发展出一种导弹拦截系统。但是这种导弹拦截系统有一个缺陷:虽然它的第一发炮弹能够到达任意的高度,但是以后每一发炮弹都不能高于前一发的高度。某天,雷达捕捉到敌国的导弹来袭。由于该系统还在试用阶段,所以只有一套系统,因此有可能不能拦截所有的导弹。
输入导弹依次飞来的高度(雷达给出的高度数据是不大于30000的正整数),计算这套系统最多能拦截多少导弹,如果要拦截所有导弹最少要配备多少套这种导弹拦截系统。
AC代码

int a[101],dp[101];//数组a记录导弹飞来的高度,dp[i]记录打中第i枚导弹以后,含第i枚导弹在内一共最多可以打dp[i]枚int max1(int a,int b)//比较函数,为防止函数名与头文件冲突,将其命名为max1{    return a>b?a:b;}int main(){    int n=1,i,j,max=0,min=0;//i、j为循环变量,max记录最多能拦截多少导弹,min记录最少要配备多少套这种导弹拦截系统    while(scanf("%d",&a[n])!=EOF)//一个输入的技巧        n++;    n--;//由于n多加了1,所以要将其自减,n记录数组a中元素的个数    for(i=1;i<=n;i++)    {        dp[i]=1;//因为如果打第i枚导弹,那么dp[i]至少为1(必须)        for(j=1;j<=i-1;j++)            if(a[i]<=a[j])//如果第i枚导弹的高度小于等于第j枚导弹的高度                dp[i]=max1(dp[i],dp[j]+1);//就将dp[i]与dp[j]+1相比较(必须)        max=max1(max,dp[i]);//max保存较大值(必须)    }    memset(dp,0,sizeof(dp));//清零dp数组,防止对第二小问的计算产生影响    for(i=1;i<=n;i++)//第二小问将于下文给出解析    {        dp[i]=1;        for(j=1;j<=i-1;j++)        if(a[i]>a[j])            dp[i]=max1(dp[i],dp[j]+1);        min=max1(min,dp[i]);//最长上升序列    }    printf("%d\n%d\n",max,min);//打印    return 0; }

解决方法:这道题是经典的最长不下降子序列问题,解决本题只需要将最长不下降子序列的思想转化为求最长不上升子序列,解决动态规划问题的关键就是正确地写出状态转移方程。一个不错的方法就是从样例入手,在草稿本上列出表格,进行手算,以发现其中的状态转移的规律,从而得出状态转移方程。

关于第二问,一个简单的解法是使用定理:一个序列中不上升子序列的最小覆盖数等于序列中最长上升序列的长度

阅读全文
0 0