算法笔记17.最长上升(不下降)子序列系列题目

博客围绕算法题目展开,包含最长不下降子序列问题,给出题目描述、输入输出要求及代码;还涉及抄近路、魔法石矿讲解,导弹拦截、楼兰宝藏等重要定理相关题目,以及和谐俱乐部、友好城市、合唱团等问题,对合唱团问题给出详细描述、解法及代码。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1.最长不下降子序列

题目描述:
Description

A numeric sequence of ai is ordered if a1 < a2 < … <aN. Let the subsequence of the given numeric sequence (a1,a2, …,aN) be any sequence (ai1,ai2, …,aiK), where 1 <=i1 < i2 < … <iK <=N. For example, sequence (1, 7, 3, 5, 9, 4, 8) has ordered subsequences, e. g., (1, 7), (3, 4, 8) and many others. All longest ordered subsequences are of length 4, e. g., (1, 3, 5, 8).

Your program, when given the numeric sequence, must find the length of its longest ordered subsequence.
Input

The first line of input file contains the length of sequence N. The second line contains the elements of sequence - N integers in the range from 0 to 10000 each, separated by spaces. 1 <= N <= 1000
Output

Output file must contain a single integer - the length of the longest ordered subsequence of the given sequence.

Sample Input

7
1 7 3 5 9 4 8


Sample Output

4

Code:

/*
Title : Longest Ordered Subsequence
Author : minisheep
Running time:47MS
Memory cost:224K
*/
#include<iostream>
#include<cstring>
#include<cstdio>
using namespace std;
const int maxn = 1001;
int a[maxn],m;
int dp[maxn];
int LIS()
{
    int i,j,temp;
    temp = 1;
    for(i=1;i<=m;i++)
    {
        dp[i] = 1;
        for(j=1;j<i;j++)
        {
            if(a[j]<a[i] && dp[j] + 1 > dp[i])  
            {
                dp[i] = dp[j] + 1;
            }
        }
        if(dp[i] > temp)
        {
            temp = dp[i];
        }
    }
    return temp;
}

int main()
{
    int i,cnt;
    while(cin>>m)
    {
        for(i=1;i<=m;i++)
        {
            cin>>a[i];
        }
        cnt = LIS();
        cout<<cnt<<endl;
    }
}

2.抄近路,魔法石矿简单讲解
(1)抄近路
在这里插入图片描述
(2)魔法石矿
在这里插入图片描述

3.一个重要定理及相关题目(导弹拦截,楼兰宝藏)
在这里插入图片描述

(1)导弹拦截问题
在这里插入图片描述

(2)楼兰宝藏
在这里插入图片描述

4.和谐俱乐部(sgu199)
在这里插入图片描述

5.友好城市,合唱团
(1)
在这里插入图片描述
(2)合唱团
1)题目描述:
N位同学站成一排,音乐老师要请其中的(N-K)位同学出列,使得剩下的K位同学不交换位置就能排成合唱队形。
合唱队形是指这样的一种队形:设K位同学从左到右依次编号为1, 2, …, K,他们的身高分别为T1, T2, …, TK,
则他们的身高满足T1 < T2 < … < Ti , Ti > Ti+1 > … > TK (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

2)解法

动态规划:
    d1表示以i结尾的左侧最长递增子序列长度
    d2表示以i开头的右侧最长递减子序列长度
    d1+d2中最大的情况是合唱队形的最优解,max中位置i计算了两次,所以长度为max-1
    需要(n-max+1)位同学出列

3)代码

#include <stdio.h>
#include <stdlib.h>
int maxnum(int x,int y)
{
    return x>y?x:y;
}
int main()
{
    int n,i,j,a[101],dp1[101],dp2[101],max;
 
    while(scanf("%d",&n)!=EOF)
    {
        for(i=0;i<n;i++)
            scanf("%d",&a[i]);
        for(i=0;i<n;i++)
        {
            dp1[i]=0;
            dp2[i]=0;
        }
        //找出以i为结尾的最长递增子序列
        for(i=0;i<n;i++)
        {
            dp1[i]=1;
            for(j=0;j<i;j++)
                if(a[i]>a[j])
                    dp1[i]=maxnum(dp1[i],dp1[j]+1);
        }
        //找出以i为开头的最长递减子序列(逆序即为递增)
        for(i=n-1;i>=0;i--)
        {
            dp2[i]=1;
            for(j=n-1;j>i;j--)
                if(a[i]>a[j])
                    dp2[i]=maxnum(dp2[i],dp2[j]+1);
        }
 
        //判断以i为最高身高的最长满足序列长度(注意i在dp1和dp2中算了两遍,最后要减去)
        max=1;
        for(i=0;i<n;i++)
        {
            if(max<(dp1[i]+dp2[i]))
                max=dp1[i]+dp2[i];
        }
        //总人数减去最长序列即为最少人数
        printf("%d\n",n-max+1);
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值