北大考研复试上机——合唱队形
2018-01-25 17:00
281 查看
N位同学站成一排,音乐老师要请其中的(N-K)位同学出列,使得剩下的K位同学不交换位置就能排成合唱队形。合唱队形是指这样的一种队形:设K位同学从左到右依次编号为1, 2, …, K,他们的身高分别为T1, T2, …, TK,则他们的身高满足T1 < T2 < … < Ti , Ti > Ti+1 > … > TK (1 <= i <= K)。你的任务是,已知所有N位同学的身高,计算最少需要几位同学出列,可以使得剩下的同学排成合唱队形。
示例1
思路:这是一个动态规划里最长上升(下降)子序列的问题,只不过分成两部分。大致过程就是对于每个学生k,计算以其为中心的队形的最大长度,也就是说,①0~k这k个学生的某个子序列高度是升序的且一定是包括k本人的;②k~N这N-k+1个学生的某个子序列的高度是降序的,同样包括k本人。
这样就把这个问题分成了两个计算最长上升(下降)子序列的问题了,这两个子序列的长度之和减一(因为要减去一个重复的k本人)就是以k为中心的最长队形,计算出以每个人为中心的最长队形,其最大值就是题目要求的数字了。
以最长0~k的最长上升子序列为例,递推公式如下:
dp[k] = 1;
dp[i] = max{ dp[j] } + 1; (0 <= i < k && height[i] < height[j] && i < j <= k)
dp[i]表示从i到k的最长上升子序列,一定包括i和k这两个人,j是i之后的某个人,如果j到k有一个子序列且i的高度小于j的高度,那在这个序列前方加上i仍旧是一个子序列,序列长度加一。而如果j到k没有子序列,那i到k之间也就没有包含j的队列。最终算出的dp[l]的最大值(0 <= l <= k)就是以k为末尾的最长的上升子序列了。
输入描述:
输入的第一行是一个整数N(2 <= N <= 100),表示同学的总数。 第一行有n个整数,用空格分隔,第i个整数Ti(130 <= Ti <= 230)是第i位同学的身高(厘米)。
输出描述:
可能包括多组测试数据,对于每组数据, 输出包括一行,这一行只包含一个整数,就是最少需要几位同学出列。
示例1
输入
8 186 186 150 200 160 130 197 220
输出
4
思路:这是一个动态规划里最长上升(下降)子序列的问题,只不过分成两部分。大致过程就是对于每个学生k,计算以其为中心的队形的最大长度,也就是说,①0~k这k个学生的某个子序列高度是升序的且一定是包括k本人的;②k~N这N-k+1个学生的某个子序列的高度是降序的,同样包括k本人。
这样就把这个问题分成了两个计算最长上升(下降)子序列的问题了,这两个子序列的长度之和减一(因为要减去一个重复的k本人)就是以k为中心的最长队形,计算出以每个人为中心的最长队形,其最大值就是题目要求的数字了。
以最长0~k的最长上升子序列为例,递推公式如下:
dp[k] = 1;
dp[i] = max{ dp[j] } + 1; (0 <= i < k && height[i] < height[j] && i < j <= k)
dp[i]表示从i到k的最长上升子序列,一定包括i和k这两个人,j是i之后的某个人,如果j到k有一个子序列且i的高度小于j的高度,那在这个序列前方加上i仍旧是一个子序列,序列长度加一。而如果j到k没有子序列,那i到k之间也就没有包含j的队列。最终算出的dp[l]的最大值(0 <= l <= k)就是以k为末尾的最长的上升子序列了。
#include <memory> #include <iostream> using namespace std; int child_left(int *height, int n) { if(n == 1) return 1; int dp ; memset(dp, 0, sizeof(dp)); dp[n-1] = 1; for(int i = n-2; i >= 0; i--) { int maxn = -1; for(int j = i+1; j <= n-1; j++) { if(height[i] < height[j] && dp[j] != -1) maxn = max(maxn, dp[j] + 1); } dp[i] = maxn; } int retVal = -1; for(int i = 0; i < n; i++) retVal = max(retVal, dp[i]); return retVal; } int child_right(int *height, int n) { if(n == 1) return 1; int dp ; memset(dp, 0, sizeof(dp)); dp[0] = 1; for(int i = 1; i <= n-1; i++) { int maxn = -1; for(int j = 0; j < i; j++) { if(height[i] < height[j] && dp[j] != -1) maxn = max(maxn, dp[j] + 1); } dp[i] = maxn; } int retVal = -1; for(int i = 0; i < n; i++) retVal = max(retVal, dp[i]); return retVal; } int cal(int *height, int n, int index) { if(index > 0 && index + 1 < n) return child_left(height, index + 1) + child_right(height + index, n - index) - 1; else if(index == 0) return child_right(height, n); else return child_left(height, n); } int main() { int n; while(cin >> n) { int height , maxlen = -1; for(int i = 0; i < n; i++) { cin >> height[i]; } for(int i = 0; i < n; i++) { maxlen = max(cal(height, n, i), maxlen); } cout << n - maxlen << endl; } }
相关文章推荐
- 北大考研复试上机——W's Cipher
- 北大考研复试上机——日志排序
- 北大考研复试上机——Is It A Tree?
- 北大考研复试上机——放苹果
- 北大考研复试上机——Repeater
- 2016北邮计算机考研复试上机题解
- 北邮考研复试C语言上机题目精选
- 深搜:西工大2015年考研复试上机最后一题(连阴雨问题)
- 北京航空航天大学计算机系考研复试上机真题及答案---2014
- 2015北邮计算机考研复试上机题解
- 2014年天勤计算机考研复试上机练习赛(2):世界杯来了
- 清华考研复试上机——玛雅人的密码
- 2012北邮计算机考研复试上机题解
- 西安电子科技大学2018考研复试计算机类上机试题总结
- 2014北邮计算机考研复试上机题解(上午+下午)
- 2014北邮计算机考研复试上机题解(上午+下午)
- 清华考研复试上机——最大序列和
- 考研复试-----C语言上机操作(二)
- 2013北邮计算机考研复试上机题解
- 浙江大学计算机学院2007年考研复试上机题