动态规划之合唱队形问题(最长递增子序列变形)

题目描述 
N位同学站成一排,音乐老师要请其中的(N-K)位同学出列,使得剩下的K位同学不交换位置就能排成合唱队形。

合唱队形定义:设K位同学从左到右依次编号为1, 2, …, K,他们的身高分别为T1, T2, …, TK,

则他们的身高满足T1 < T2 < … < Ti, Ti > Ti+1 > … > TK (1 <= i <= K)。 
要求:已知所有N位同学的身高,计算最少需要几位同学出列,可以使得剩下的同学排成合唱队形。

输入 
输入的第一行是一个整数N,表示同学的总数。 
第一行有n个整数,用空格分隔,第i个整数Ti是第i位同学的身高(厘米)。

输出 
输出包括一行,这一行只包含一个整数,就是最少需要几位同学出列。

解题思路 
定义n位同学的身高数组为a[n](注意这里数组长度不允许为变量,这里只是为了理解将n写如到[]中)。

总体思路】:假设第i(0<= i <= n - 1)个同学为最高点,分别求出此时i左边的最长递增子序列长度inc1[i],i右边的最长递减子序列长度inc2[i],由于最高点i同时包括在了inc1[i]和inc2[i]之中,因此实际的合唱队形的长度为inc1[i] + inc2[i] - 1。而我们求得的最后结果就是i从1到n - 1中,使得inc1[i] + inc2[i] - 1最大的情况。

具体实现】:现在设i为下标,循环i从0到n-1,求得各种i值对应的inc1[i];循环i从0到n-1,求得各种i值对应的inc2[i]。最后循环i从0到n-1,求得各种i值对应的inc[i] + inc2[i] - 1最大的情况ans,然后n - ans即为出列同学的人数。

当i = 0的时候,最高点0左边只有它自己,因此inc1[0] = 1;当i = n - 1的时候,最高点n - 1右边只有它自己,因此inc2[n - 1] = 1;当i处于0到n - 1之间时的求法也很好理解,在求inc1[i]时,j = (0 ~ i - 1)的inc[j]已经得出来了,所以我们只需要比较在前面的这些序列中加上a[i]时的最长递增序列,即在a[i]大于前面这些序列值的情况下inc[j] + 1最大的情况即为inc[i]。

源代码如下:

#include <iostream>
#include <stdio.h>
using namespace std;

int inc1[200],inc2[200],a[200];
//inc1-->longest increase array from head to tail
//inc2-->longest increase array from tail to head

int main()
{
    int n;
    while(scanf("%d",&n)!=EOF)
    {
        int ans=0,i,j;
        for(i = 0; i < n; i++)  //输入n个人的身高
            scanf("%d",&a[i]);

        //inc1[i]是存储以i为最高点时左边的递增子序列长度
        inc1[0]=1;
        for(i = 1; i < n; i++)
        {
            inc1[i] = 1;
            for(j = 0; j < i; j++)
                if(a[i] > a[j] && inc1[j] + 1 > inc1[i])
                    inc1[i] = inc1[j]+1;
        }

        //inc2[i]是存储以i为最高点时左边的递减子序列长度
        inc2[n - 1] = 1;
        for(i = n - 2; i >= 0; i--)
        {
            inc2[i] = 1;
            for(j = n - 1; j > i; j--)
                if(a[j] < a[i] && inc2[j] + 1 > inc2[i])
                    inc2[i] = inc2[j] + 1;
        }

        for(i = 0; i<=n; i++)
            if(inc1[i] + inc2[i]-1 > ans) 
                ans = inc1[i] + inc2[i] - 1;
        printf("%d\n",n-ans);
    }
    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
提供的源码资源涵盖了Java应用等多个领域,每个领域都包含了丰富的实例和项目。这些源码都是基于各自平台的最新技术和标准编写,确保了在对应环境下能够无缝运行。同时,源码中配备了详细的注释和文档,帮助用户快速理解代码结构和实现逻辑。 适用人群: 适合毕业设计、课程设计作业。这些源码资源特别适合大学生群体。无论你是计算机相关专业的学生,还是对其他领域编程感兴趣的学生,这些资源都能为你提供宝贵的学习和实践机会。通过学习和运行这些源码,你可以掌握各平台开发的基础知识,提升编程能力和项目实战经验。 使用场景及目标: 在学习阶段,你可以利用这些源码资源进行课程实践、课外项目或毕业设计。通过分析和运行源码,你将深入了解各平台开发的技术细节和最佳实践,逐步培养起自己的项目开发和问题解决能力。此外,在求职或创业过程中,具备跨平台开发能力的大学生将更具竞争力。 其他说明: 为了确保源码资源的可运行性和易用性,特别注意了以下几点:首先,每份源码都提供了详细的运行环境和依赖说明,确保用户能够轻松搭建起开发环境;其次,源码中的注释和文档都非常完善,方便用户快速上手和理解代码;最后,我会定期更新这些源码资源,以适应各平台技术的最新发展和市场需求。 所有源码均经过严格测试,可以直接运行,可以放心下载使用。有任何使用问题欢迎随时与博主沟通,第一时间进行解答!

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值