洛谷_1091_合唱队行

题目描述

N位同学站成一排,音乐老师要请其中的(N-K)位同学出列,使得剩下的K位同学排成合唱队形。

合唱队形是指这样的一种队形:设K位同学从左到右依次编号为1,2,…,K,他们的身高分别为T_1,T_2,…,T_K, 则他们的身高满足T1T_1<…<TiT_i>Ti+1T_{i+1}>…>TK(1iK)T_K(1 \leq i \leq K)

你的任务是,已知所有N位同学的身高,计算最少需要几位同学出列,可以使得剩下的同学排成合唱队形。

输入格式

共二行。

第一行是一个整数N(2N100)N(2 \le N \le 100),表示同学的总数。

第二行有n个整数,用空格分隔,第i个整数Ti(130Ti230)T_i(130 \le T_i \le 230)是第i位同学的身高(厘米)。

输出格式

一个整数,最少需要几位同学出列。

输入输出样例

输入 #1复制

8
186 186 150 200 160 130 197 220

输出 #1复制

4

说明/提示

对于50%的数据,保证有n20n \le 20

对于全部的数据,保证有n100n \le 100

思路:

其实思路就是挺好想的,因为数据规模不大,所以枚举以第 i 个数为最高点时的队列长度,然后选出最长的即可得到排除最少的人数。

而如何计算最长队列呢?很显然,只要算出 i 之前的最长升序子序列(并且末尾元素小于第 i 个元素)和 i 之后的最长降序子序列(并且首元素小于第 i 个元素)。

代码:

/*思路:转换思路 -> 求最长升序子序列和最长降序子序列 */
#include <cstdio>
#include <climits>
#include <algorithm>
using namespace std;

const int MAX = 110;
int N;
struct data
{
	int d,l,r;	
}datas[MAX];

int results[MAX];

void get_maxDecrease()
{
	for(int i = N;i >= 1;i--){
		datas[i].r = 1;
		for(int j = N;j > i;j--)
			if(datas[i].d > datas[j].d)
				datas[i].r = max(datas[i].r,datas[j].r + 1);
	}
}

//获取以site为结尾的最大长度 
void get_maxIncrease() 
{
	for(int i = 1;i <= N;i++){
		datas[i].l = 1;
		for(int j = 1;j < i;j++)
			if(datas[i].d > datas[j].d)
				datas[i].l = max(datas[i].l,datas[j].l + 1);
	}
}

void init() 
{
	get_maxIncrease();
	get_maxDecrease();
	return ;
}

int get_right(int i)
{
	int myMax = 0;
	for(int j = N;j > i;j--)
		if(datas[j].d < datas[i].d&&myMax < datas[j].r)
			myMax = datas[j].r;
	return myMax;	
}

int get_left(int i)
{
	int myMax = 0;
	for(int j = 1;j < i;j++)
		if(datas[j].d < datas[i].d&&myMax < datas[j].l)
			myMax = datas[j].l;
	return myMax;
}

int get_ans()
{
	int num = 0;
	for(int i = 1;i <= N;i++){
		int left = get_left(i);		
		int right = get_right(i);	
		left = i-1-left;
		right = N-i-right;
		num = left + right;
		results[i] = num;
	}	 
	int myMin = INT_MAX;
	for(int i = 1;i <= N;i++)
		if(myMin > results[i])
			myMin = results[i];
	return myMin;
}

int main()
{
	//读入数据并初始化: 
	scanf("%d",&N);
	for(int i = 1;i <= N;i++)
		scanf("%d",&datas[i].d);
	init();

	//处理:
	int ans = get_ans();
			
	//输出:
	printf("%d",ans);
	
	return 0;
}

总结:

这道题我一开始做错了,至于原因我也不陈述了(比较麻烦),但结论是,对于熟悉或者工具类的算法我们不要随意根据题更改,而要尽量像调用API一样使用它们。这样做有两个好处,一是不容易出错,二是久而久之这些常用代码(例如本题的最长子序列、二分查找之类的)会越来越熟悉。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章