洛谷 P1091 合唱队形

该篇文章介绍了如何使用动态规划方法解决一个问题,即在一定条件下找出最少需要让多少学生出列,以便剩余学生可以按照身高形成递增或递减的合唱队形。通过计算递增子序列的元素数量来确定最优解。
摘要由CSDN通过智能技术生成

题目描述

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;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

3分人生

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值