题目描述
n 位同学站成一排,音乐老师要请其中的 n−k 位同学出列,使得剩下的 k 位同学排成合唱队形。
合唱队形是指这样的一种队形:设 k 位同学从左到右依次编号为 1,2,1,2, … ,k,他们的身高分别为 t1,t2, … ,tk,则他们的身高满足 t1<⋯<ti>ti+1> … >tk(1≤i≤k)。
你的任务是,已知所有 n 位同学的身高,计算最少需要几位同学出列,可以使得剩下的同学排成合唱队形。
输入格式
共二行。
第一行是一个整数 n(2≤n≤100),表示同学的总数。
第二行有 n 个整数,用空格分隔,第 i 个整数 ti(130≤ti≤230)是第 i 位同学的身高(厘米)。
输出格式
一个整数,最少需要几位同学出列。
输入输出样例
输入 #1
8 186 186 150 200 160 130 197 220
输出 #1
4
说明/提示
对于 50% 的数据,保证有 n≤20。
对于全部的数据,保证有 n≤100。
解题思路
本题考察的是动态规划中递增子序列问题,dp[ i ]表示以下标为i结尾的递增子序列的元素数量,递推公式是dp[ i ]=max(dp[ i ], dp[ j ]+1);条件是a[ i ]>a[ j ];递增序列越大,要删减的数量就越少;
AC代码
#include<stdio.h>
//f,g判断原序列是否是递增或递减,b数组是a数组的倒序
int n, a[101], b[101], dp1[101], dp2[101], i, j, f = 0, g = 0;
int main()
{
scanf("%d", &n);
for (i = 1; i <= n; i++)
{
scanf("%d", &a[i]);
if (i > 1 && a[i] > a[i - 1])
f = 1;
if (i > 1 && a[i] < a[i - 1])
g = 1;
b[n - i + 1] = a[i];
//dp数组初始化
dp1[i] = 1;
dp2[i] = 1;
}
if (f == 0 || g == 0)//如果原序列为递增或递减
{
printf("0");
return 0;
}
//dp递推公式
for (i = 2; i <= n; i++)
for (j = 1; j < i; j++)
{
if (a[i] > a[j]&&dp1[i] < dp1[j] + 1)
dp1[i] = dp1[j] + 1;
if (b[i] > b[j] && dp2[i] < dp2[j] + 1)
dp2[i] = dp2[j] + 1;
}
//求最小删除数量
int max = 1e9;
for (i = 1; i < n; i++)
for (j = 1; j <= n - i; j++)
if (a[i] != b[j] && max > n - dp1[i] - dp2[j])
max = n - dp1[i] - dp2[j];
printf("%d", max);
return 0;
}