洛谷 P1970 花匠
阿新 • • 發佈:2018-11-29
題目描述
花匠棟棟種了一排花,每株花都有自己的高度。花兒越長越大,也越來越擠。棟棟決定把這排中的一部分花移走,將剩下的留在原地,使得剩下的花能有空間長大,同時,棟棟希望剩下的花排列得比較別緻。
具體而言,棟棟的花的高度可以看成一列整數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 inti=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; }