• 洛谷 P1970 花匠


    题目描述

    花匠栋栋种了一排花,每株花都有自己的高度。花儿越长越大,也越来越挤。栋栋决定把这排中的一部分花移走,将剩下的留在原地,使得剩下的花能有空间长大,同时,栋栋希望剩下的花排列得比较别致。

    具体而言,栋栋的花的高度可以看成一列整数h1,h2...hn。设当一部分花被移走后,剩下的花的高度依次为g1,g2...gm,则栋栋希望下面两个条件中至少有一个满足:

    注意上面两个条件在m=1时同时满足,当m>1时最多有一个能满足。

    请问,栋栋最多能将多少株花留在原地。

    思路

    (这种算法很慢,而且比起贪心可能更难理解。但是在dp中算是最直接的一种办法

    首先看到这题很容易想到LIS(最长上升子序列)

    于是开两个数组表示条件a和条件b,一个整数i表示到第i个数的最大长度,并用0或1来表示接下来要选更大的还是更小的。

    然后就……就TLE了。代码:

    #include<iostream>
    
    using namespace std;
    
    int a[100005],fa[100005][2],fb[100005][2],n;
    
    int main()
    {
        cin>>n;
        for(int i=1;i<=n;i++)
            cin>>a[i];
        fa[1][0]=fb[1][0]=fa[1][1]=fb[1][1]=1;
        for(register int i=2;i<=n;i++)
        {
            for(register int j=1;j<i;j++)
            {
                if(a[j]<a[i])
                {
                    fb[i][1]=max(fb[i][1],fb[j][0]+1);
                    fa[i][0]=max(fa[i][0],fa[j][1]+1);
                }
                if(a[j]>a[i])
                {
                    fb[i][0]=max(fb[i][0],fb[j][1]+1);
                    fa[i][1]=max(fa[i][1],fa[j][0]+1);
                }
            }
        }
        cout<<max(fb[n][0],max(fa[n][1],max(fb[n][1],fa[n][0])));
        return 0;
    }

    但是这题不像LIS,它只需要上一个数比他小(大)就行了,只要在前面找到一个比他小的数,那就肯定表明这个数之前的序列都更短。

    所以每次从后往前搜,能转移就转移。更大和更小都转移完了之后,就能够从中选取答案了。

    代码:

    #include<iostream>
    using namespace std;
    
    int a[100005],fa[100005][2],fb[100005][2],n;
    bool flag1,flag2;
    
    int main()
    {
        cin>>n;
        for(int i=1;i<=n;i++)
            cin>>a[i];
        fa[1][0]=fb[1][0]=fa[1][1]=fb[1][1]=1;
        for(register int i=2;i<=n;i++)
        {
            flag1=flag2=1;
            for(register int j=i;j>=0&&(flag1||flag2);j--)
            {
                if(a[j]<a[i])
                {
                    flag1=0;
                    fb[i][1]=max(fb[i][1],fb[j][0]+1);
                    fa[i][0]=max(fa[i][0],fa[j][1]+1);
                }
                if(a[j]>a[i])
                {
                    flag2=0;
                    fb[i][0]=max(fb[i][0],fb[j][1]+1);
                    fa[i][1]=max(fa[i][1],fa[j][0]+1);
                }
            }
        }
        cout<<max(fb[n][0],max(fa[n][1],max(fb[n][1],fa[n][0])));
        return 0;
    }
  • 相关阅读:
    三、视频操作
    C# SendKeys使用方法介绍
    3.如已交60%档,现想交提高缴费档次该怎么办?
    四、答疑解惑
    C# 获取当前网页HTML
    (二)灵活就业人员养老保险和医疗保险
    字符编码(转)
    .NET跨页面传值的方法
    正则表达式之匹配关系(转)
    javascript对DOM的常用操作
  • 原文地址:https://www.cnblogs.com/ehznehc/p/10040863.html
Copyright © 2020-2023  润新知