动态规划dp--------合唱队形

题目描述

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

合唱队形是指这样的一种队形:设K位同学从左到右依次编号为1,2,…,K,他们的身高分别T1,T2,…,TK,则他们的身高满足T1<…<Ti>Ti+1>…>TK(1≤i≤K)(1≤i≤K) 。

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

输入描述

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

输出描述

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

样例

输入

8
186 186 150 200 160 130 197 220

输出

4

题目分析

判断这是否是个dp问题 就要看他有没有最优子结构 很明显有

这是这个题的简图 必须画图 反正我不画图做不出来

题目是要一个有尖的“数列” 所以有个数很大 并且是要尖前面的位置成上升 后面的位置成下降

假设第i个数很大 那么就是前1-i里面求一个LIS最长上升子序列 后i-n个求最长下降子序列

当然这个地方不好求一个最长下降子序列 所以我们倒着从n-i求一个最长上升子序列

这里如果是求n-i的最长上升序列的话 我们要到(从)i+1这个位置

想想 如果当前为i 那么下一个位置就为i+1

最后比较求一个最大值

所以设置一个temp来存储 当前两个的值 但是这样会多算一个i

所以减去一个1

但是求的这个maxx是可以留多少人

题目中让求的是踢出多少人 所以要让n-maxx

输出即可

AC如下:

#include<iostream>
using namespace std;
const int N=105;
int qiandp[N],num[N],cnt,cmt,houdp[N];
int n;
int main(){
    cin>>n;
    for(int i=1;i<=n;i++){
        cin>>num[i];
        qiandp[i]=1;
        houdp[i]=1;
    }
//    for(int i=1;i<=n;i++){
//        qiandp[i]=1;
//        houdp[i]=1;
//    }
    for(int i=1;i<=n;i++){
        for(int j=1;j<=i-1;j++){
            if(num[i]>num[j]&&qiandp[i]<qiandp[j]+1){
                qiandp[i]=qiandp[j]+1;
            }
        }
    }
    for(int i=n;i>=1;i--){
        for(int j=n;j>=i+1;j--){
            if(num[i]>num[j]&&houdp[i]<houdp[j]+1){
                houdp[i]=houdp[j]+1;
            }
        }
    } 
//    for(int i=1;i<=n;i++){
//        cout<<qiandp[i]<<" ";
//    }
//    cout<<endl;
//    for(int i=n;i>=1;i--){
//        cout<<houdp[i]<<" ";
//    }
    int maxx=0;
    for(int i=1;i<=n;i++){
        int temp=qiandp[i]+houdp[i]-1;
        maxx=max(maxx,temp);
    }
    cout<<n-maxx;
    
    
    
    //i为终点的最长上升子序列 以n为起点 以i为终点的最长上升子序列     
    return 0;
 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值