初入DP:最长上升子序列(LIS)

Description
我们都知道上体育课时,体育老师会让我们按身高从小到大(或从大到小)排成一排。可是近日体育老师周老师却有点烦心,
他教的班级来了几个插班生,可他们有的不守规矩,没有按照身高大小来插入队伍,导致队伍很难看。现在周老师有一个问
题:给定一排人的身高,问能否至多去掉一个人,使得队伍里的人的身高又变成从小到大(或从大到小)?

注意: 如果一排人的身高为 1 2 2 或 2 2 1是合法的。

输入格式
第一行一个整数T,表示case数
接着是一个n,表示有n个人
接着是n个整数,第i个整数表示第i个人身高为a[i]
T <= 1000 , 2 <= n <= 1000 , a[i] <= 10000

输出格式
如果可以,输出”YES”,否则输出”NO”。每个case占一行。

输入样例
3
3
1 4 5
3
9 2 3
5
1 5 2 4 3

输出样例
YES
YES
NO
分析:题目意思很明确,就是找最长上升子序列或最长下降子序列的长度,看是否大于等于n-1,那么最长上升子序列是个什么东东呢?现在我们一起来看看吧!

LIS:
最长上升子序列涉及的算法是DP,为什么呢?因为我们求一个长度为n的LIS可以通过求长度为n-1的LIS,再加上一,而长度为n-1的LIS又可以由求长度为n-2的LIS加一得到,以此类推。符合把DP思想中的把问题分解为更小的子问题,而且全局最优解由局部最优解得到。

我们举个栗子吧
2 7 1 5 6 4 3 8 9 用数组num[i]来表示到数组a[i]为止的最长上升子序列
一开始给num[i]全部赋值为1(因为最短的上升子序列为它自己本身)
为了方便,序列由1开始编号
1.a[1] = 2,num[1] = 1;
2.a[2] = 7,前面序列为2,2比7小,那么num[2] = num[1] + 1=2;
3.a[3] = 1,前面序列为2,7,没有比它小的,则num[3] = 1;
4.a[4] = 5,前面序列为2,7,1,前面比它小的是2,则num[4] = num[1] + 1=2;
5.a[5] = 6,前面序列为2,7,1,5,前面比它有2,5,则num[5] = num[4] + 1=3;
6.a[6] = 4,前面序列为2,7,1,5,6,前面比它小有2,则num[6] = num[1] + 1=2;
7.a[7] = 3,前面序列为2,7,1,5,6,4,前面比它小2,则num[7] = num[1] + 1;
8.a[8] = 8,前面序列为2,7,1,5,6,4,3,前面比它小有2,5,6,则num[8] = num[5] + 1 = 4;
9.a[9] = 9,前面序列为2,7,1,5,6,4,3,8,前面比它小有2,5,6,8,则num[9] = num[8] + 1= 5;
那么最后一步就是在num[i]中找最大的值,即为序列的最长上升子序列的长度。
总结:就是在a[i]中找a[1]到a[i]中最长上升子序列,然后把到每个位置的最长上升子序列长度存起来,最后再比较各位置时的最长上升子序列长度,找到最大值即可。

#include <stdio.h>
int a[1005],b[1005];
int list1(int n)
{
    int num[1005],i,j,maxx;
    for(i=0; i<n; i++)
    {
        num[i] = 1;
        for(j=0; j<i; j++)
        {
            if((a[j] <= a[i]) && (num[j] + 1 >num[i]))
                num[i] = num[j] + 1;
        }
    }
    for(i=0; i<n; i++)
    {
        if(i==0 || num[i] > maxx)
            maxx = num[i];
    }
    return maxx;
}

int list2(int n)
{
    int num[1005],i,j,maxx;
    for(i=0; i<n; i++)
    {
        num[i] = 1;
        for(j=0; j<i; j++)
        {
            if((a[j] >= a[i]) && (num[j] + 1 >num[i]))
                num[i] = num[j] + 1;
        }
    }
    for(i=0; i<n; i++)
    {
        if(i==0 || num[i] > maxx)
            maxx = num[i];
    }
    return maxx;
}

int main()
{
   int kase,n,i,result1,result2;
   scanf("%d",&kase);
   while(kase--)
   {
       scanf("%d",&n);
       for(i=0; i<n; i++)
          scanf("%d",&a[i]);
       result1 = list1(n);
       result2 = list2(n);
       if(result1 >= n-1 || result2 >= n-1)
          printf("YES\n");
       else
          printf("NO\n");
   }
}

猜你喜欢

转载自blog.csdn.net/weixin_43678350/article/details/84791137
今日推荐