1. 程式人生 > >洛谷 P1970 花匠

洛谷 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;
}