洛谷_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一樣使用它們。這樣做有兩個好處,一是不容易出錯,二是久而久之這些常用代碼(例如本題的最長子序列、二分查找之類的)會越來越熟悉。

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