动态规划:P1091 [NOIP2004 提高组] 合唱队形
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)//从左边计算上升序列 13 for (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),因为数据范围比较小,也能顺利通过。
这是通过图: