0
点赞
收藏
分享

微信扫一扫

[动态规划]HJ24 合唱队-中等

​​HJ24 合唱队​​

描述

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

[动态规划]HJ24 合唱队-中等_数据位同学从左到右依次编号为 1,2…,K ,他们的身高分别为[动态规划]HJ24 合唱队-中等_数据_02 ,若存在[动态规划]HJ24 合唱队-中等_数据_03 使得[动态规划]HJ24 合唱队-中等_动态规划_04 且 [动态规划]HJ24 合唱队-中等_数据_05,则称这[动态规划]HJ24 合唱队-中等_数据名同学排成了合唱队形。

通俗来说,能找到一个同学,他的两边的同学身高都依次严格降低的队形就是合唱队形。

例子:

123 124 125 123 121 是一个合唱队形

123 123 124 122不是合唱队形,因为前两名同学身高相等,不符合要求

123 122 121 122不是合唱队形,因为找不到一个同学,他的两侧同学身高递减。


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


注意:不允许改变队列元素的先后顺序  不要求最高同学左右人数必须相等


数据范围: [动态规划]HJ24 合唱队-中等_数据_07


输入描述:

用例两行数据,第一行是同学的总数 N ,第二行是 N 位同学的身高,以空格隔开

输出描述:

最少需要几位同学出列

示例1

输入:

8
186 186 150 200 160 130 197 200

复制

输出:

4

说明:

由于不允许改变队列元素的先后顺序,所以最终剩下的队列应该为186 200 160 130或150 200 160 130

题解

动态规划解法

思路:

根据题意,假设我们选取索引为i的同学作为中间人选,则只需要求出[0,i-1]的最长递增序列,以及[i+1,n-1]的最长递减序列即可知道最少的出队次数。

步骤:

  1. 使用inc_dp[i]表示从左到右遍历时以索引i结束时的最长递增序列长度
  2. 使用dec_dp[i]表示从左到右遍历时以索引i结束时的最长递减序列长度
  3. inc_dp初始条件:inc_dp[0] = 1,表示只有一个元素
  4. 推导条件:dp[i] = max(dp[i],dp[k] + 1),其中k是[0,i-1]范围内的元素,且height[k] < height[i],表示取前[0,k]个元素作为递增序列的时候,再加上第i个元素能组成的递增序列长度
  5. dec_dp的初始化、推导条件和inc_dp类似
  6. 求解:遍历整个数组,以索引i为中心时需要出队的长度len = height.size() - (inc_dp[i]+dec_dp[i]-1),也就是总人数减去以i为中心索引时左边的递增长度、右边的递减长度

代码如下:

#include<iostream>
#include<string>
#include<vector>
#include<algorithm>
using namespace std;


int solve(const std::vector<int> &v)
{
std::vector<int> inc_dp(v.size(),1);
std::vector<int> dec_dp(v.size(),1);
for (int i = 1;i < v.size();++i)
{
for (int k = i - 1;k >= 0;--k)
{
if (v[i] > v[k])
{
inc_dp[i] = std::max(inc_dp[k]+1,inc_dp[i]);
}
else if (v[i] == v[k])
{
inc_dp[i] = std::max(inc_dp[i],inc_dp[k]);
}
}
}
for (int i = v.size() - 1;i > 0;--i)
{
for (int k = i + 1;k < v.size();++k)
{
if (v[i] > v[k])
{
dec_dp[i] = std::max(dec_dp[k]+1,dec_dp[i]);
}
else if (v[i] == v[k])
{
dec_dp[i] = std::max(dec_dp[i],dec_dp[k]);
}
}
}

int len = 0;
for (int i = 0;i < v.size();++i)
{
len = std::max(len,(inc_dp[i] + dec_dp[i] - 1));
}
return v.size() - len;
}

int main()
{
int n;
std::cin >> n;
std::vector<int> v(n, 0);
for (int i = 0; i < n; ++i)
{
std::cin >> v[i];
}
std::cout << solve(v) << std::endl;
return 0;
}


举报

相关推荐

0 条评论