P1091 合唱隊形題解(洛谷,動態規劃LIS,單調佇列)
阿新 • • 發佈:2018-11-17
先上題目
P1091 合唱隊形(點選開啟題目)
題目解讀:
1.由T1<...<Ti和Ti>Ti+1>…>TK可以看出這題涉及最長上升子序列和最長下降子序列
2.注意點:當n=1時是允許的,就是說沒有因為i=1,Ti=T1,所以最後全部人都要出列這種說法
初步思路:
建立兩個函式,一個引數為l,r,判斷l~r內最長上升子序列的最大長度,另外一個函式判斷l~r內最長下降子序列的最大長度,無論你是先高後低,還是一路升高還是一路降低都可以用這兩個函式解決
讓i=1~n,然後最大的那個left(1,i)+right(i,n)-1就是能擁有的最大合唱團人數(減一是因為i在左右兩邊序列都有,重複了,所以減一 )
合唱團人數最多,當然被淘汰的人最少啦
總人數-最多合唱團人數=最少剔除人數
上ac程式碼:
#include<bits/stdc++.h> #define ll long long using namespace std; const int maxn=100+10; int f[maxn]; int a[maxn]; int n; int left(int l,int r)//最長上升子序列 { for(int i=1;i<=n;i++) f[i]=1;//初始化為1 for(int i=l;i<=r;i++)for(int j=l;j<=i-1;j++) if(a[i]>a[j])//如果可以附加 f[i]=max(f[i],f[j]+1); int ans=f[1]; for(int i=l;i<=r;i++) ans=max(ans,f[i]); return ans;//這一段區間的最長上升子序列 } int right(int l,int r)//最長下降子序列 {///和上面差不多,加號改成減號而已 for(int i=1;i<=n;i++) f[i]=1; for(int i=l;i<=r;i++) for(int j=l;j<=i-1;j++) if(a[i]<a[j])//如果可以附加///如果當前a[i]比較小 f[i]=max(f[i],f[j]+1); int ans=f[1]; for(int i=l;i<=r;i++) ans=max(ans,f[i]); return ans;//輸出最長下降子序列長度 } int main() { cin>>n;//輸入n for(int i=1;i<=n;i++) scanf("%d",&a[i]);//輸入資料 int temp_ans=1;//賦初值 for(int i=1;i<=n;i++)//讓ti=1~n,列舉各種ti {//temp_ans的意義是當ti為i時,符合條件的合唱團最大人數 temp_ans=max(temp_ans,left(1,i)+right(i,n)-1); } cout<<n-temp_ans<<endl;//總人數-最多合唱團人數=最少剔除人數 } /* 8 4 4 2 6 3 1222 5 7 */ /* 5 1 8 3 5 2 */