動態規劃:P1091 [NOIP2004 提高組] 合唱隊形
阿新 • • 發佈:2022-04-12
P1091 [NOIP2004 提高組] 合唱隊形
洛谷的一題黃題,可以看得出考的是動態規劃的知識點。分析題意,就是就是怎麼樣拿掉最少的人,使最終序列成為中間高,兩邊低,我們可以把這個序列看成左邊是單調上升序列,右邊是單調下降序列,問題就轉化為從左邊求每一個人的最大上升子序列,從右邊求兩個人的最大上升子序列,兩個序列的dp1和dp2的和最大的值x,則就只要拿掉n-x個人最小,就是答案。所以我們只要從左到右和從右到左,分別用一次O(n2)的DP,求出DP1和DP2陣列即可。
上程式碼:
1 //P1091 [NOIP2004 提高組] 合唱隊形 2 #include<iostream> 3#include<cmath> 4 #include<algorithm> 5 using namespace std; 6 int a[105], dp1[105], dp2[105]; 7 int main() 8 { 9 int n; 10 cin >> n; 11 for (int i = 1; i <= n; ++i)cin >> a[i], dp1[i] = 1, dp2[i] = 1;//初始化為1一下 12 for (int i = 1; i <= n; ++i)//從左邊計算上升序列 13for (int j = 1; j <= i - 1; ++j) 14 if (a[i] > a[j]) 15 dp1[i] = max(dp1[j] + 1, dp1[i]); 16 for (int i = n; i >= 1; --i) 17 for (int j = n; j >= i + 1; --j) 18 if (a[i] > a[j]) 19 dp2[i] = max(dp2[j] + 1, dp2[i]);20 int Max = -1; 21 for (int i = 1; i <= n; ++i) 22 { 23 dp1[i] += (dp2[i] - 1);//要減 因為加起來 會重複加上一個自身 24 Max = max(dp1[i], Max); 25 } 26 cout << n - Max; 27 return 0; 28 }
我的做法時間複雜度為O(N2),因為資料範圍比較小,也能順利通過。
這是通過圖: