习题12.3合唱队形(北京大学复试题)
合唱队列是升级版的 最大上升子序列问题 + 动态规划法
考虑节点i,节点i左边需要的是最大上升子序列,节点右边是最大下降子序列问题,分别用dp1[i]和dp2[i]来存储
max(dp1[i] + dp2[i] -1) 即为最大的符合条件的队列的人数,用总人数n - (dp1[i] + dp2[i] -1) 即为所求
#include<vector>
using namespace std;
int main() {
int n;
cin >> n;
vector<int> nums(n);
//1. input data
for (int i = 0; i < n; i++) {
cin >> nums[i];
}
//2. 计算i节点的最大上升子序列的长度
vector<int> dp1(n);
for (int i = 0; i < n; i++) {
dp1[i] = 1;
for (int j = 0; j < i; j++) {
if (nums[j] < nums[i]) {
dp1[i] = max(dp1[j] + 1, dp1[i]);
}
}
}
//3. 计算i节点的最大下降子序列的长度
vector<int> dp2(n);
for (int i = n - 1; i >= 0; i--) {
dp2[i] = 1;
for (int j = i+1; j < n;j++) {
if (nums[i] > nums[j]) {
dp2[i] = max(dp2[i], dp2[j] + 1);
}
}
}
//4.找到节点i使得dp1[i] + dp2[i] 人数最多,即这样满足要求的人数就越多,出队的人便越少
int ans = dp1[0] + dp2[0]-1;
for (int i = 0; i < n; i++) {
ans = max(ans, dp1[i] + dp2[i] - 1);
}
cout << n - ans << endl;
return 0;
}