NOIP200407合唱队形+最长上升子序列O(n^2)详解

合唱队形解题报告

2016-05-12   430——645


NOIP200407合唱队形


难度级别:A; 运行时间限制:1000ms; 运行空间限制:256000KB; 代码长度限制:2000000B


试题描述


N位同学站成一排,音乐老师要请其中的(N-K)位同学出列,使得剩下的K位同学排成合唱队形。
    合唱队形是指这样的一种队形:设K位同学从左到右依次编号为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位同学的身高(厘米)。


输出


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


输入示例


8
186 186 150 200 160 130 197 220


输出示例


4


其他说明


数据范围:n<=100。

 

代码:

 1 #include<iostream>
 2
 3 using namespace std;
 4
 5 int b[110],c[110],a[110];
 6
 7 //    分别定义了三个数组:数组a(用来储存输入数据),数组b(用来存储从a[1]到a[n]的最大严格上升子序列长度),数组c(用来存储从a[n]到a[1]的最大严格下降子序列长度)
 8
 9 int main()
10
11 {
12
13
14
15     int n,ans=0,i,j;
16
17     scanf("%d",&n);//输入
18
19     for(i=1;i<=n;i++) scanf("%d",&a[i]);
20
21     b[1]=1;
22
23 for(i=2;i<=n;i++)
24
25 //从a[2]开始求最大严格上升子序列长度
26
27        {
28
29         b[i]=1;
30
31         for(j=1;j<i;j++)
32
33             if(a[i]>a[j]) b[i]=max(b[i],b[j]+1);
34
35             //如果a[i]>a[j],则可能从a[1]到a[i]的最大严格上升子序列长度又增加了1。
36
37     }
38
39 c[n]=1;
40
41 //从a[n]开始求最大严格上升子序列长度
42
43     for(i=n-1;i>=1;i--)
44
45        {
46
47         c[i]=1;
48
49         for(j=n;j>i;j--)
50
51             if(a[i]>a[j]) c[i]=max(c[i],c[j]+1);
52
53             //如果a[i]<a[j],则可能从a[i]到a[n]的最大严格上升子序列长度又增加了1。
54
55     }
56
57     for(i=1;i<=n;i++)
58
59         if(b[i]+c[i]>ans) ans=b[i]+c[i];//更新答案
60
61     printf("%d",n-ans+1);//输出
62
63 }

《合唱队形》这道题其实就是《求最长下降/上升子序列》的翻版。但如果用循环直接搜固然很难办,而且不知道会用多长时间,所以,简单动态规划的思想很容易办到。

b[i]=1;

这句赋值语句固然很好理解,每一个元素,也可以视为一个符合题意的子序列,不论是最长上升、最长下降。所以从a[1]

a[i]的符合题意的子序列必将有一个。比如有如下一组数。

b[1]  1,原因如上。

b[2]呢?如图,它显然比a[1]高,在执行如下语句时

for(j=1;j<i;j++)   if(a[i]>a[j])

j小于i,也就是2,目前符合条件的只有a[1]a[1]又通过了判断语句,它确实小于a[i],执行下一条语句:

b[i]=max(b[i],b[j]+1);

b[2]显然原来是1,当它和b[1]+1比时,1当然比2小,所以,b[2]自然就是2了。由此,这个方法只需要一维数组就行了。、

O(nlogn)的方法,将下次介绍。这样的方法的时间复杂度为O(n^2)


b[1]=1;

解决完了这个问题,这道题就非常简单了,先从下往上搜一遍最长上升子序列,代码如下:

for(i=2;i<=n;i++)

       {

        b[i]=1;

        for(j=1;j<i;j++)

            if(a[i]>a[j])
b[i]=max(b[i],b[j]+1);

}

再反着从上往下搜一下最长上升子序列:

这段代码一定就很好理解了:

for(i=1;i<=n;i++)

        if(b[i]+c[i]>ans) ans=b[i]+c[i];

一直更新ans,要求出队人数最少,自然要让保留人数最多。

最后输出n-ans+1

时间: 2024-08-01 10:30:48

NOIP200407合唱队形+最长上升子序列O(n^2)详解的相关文章

P1091 合唱队形 最长上升子序列

思路:最长上升子序列 正着做一遍 倒着做一遍 然后 取最大值 #include<bits/stdc++.h> using namespace std; const int maxn=105; int dp[maxn],dp1[maxn],a[maxn]; int main(){ int n; cin>>n; for(int i=1;i<=n;i++)scanf("%d",&a[i]); for(int i=1;i<=n;i++){ dp[i]

最长上升子序列O(nlogn)算法详解

最长上升子序列 时间限制: 10 Sec   内存限制:128 MB 题目描述 给定一个序列,初始为空.现在我们将1到N的数字插入到序列中,每次将一个数字插入到一个特定的位置.我们想知道此时最长上升子序列长度是多少? 输入 第一行一个整数N,表示我们要将1到N插入序列中,接下是N个数字,第k个数字Xk,表示我们将k插入到位置Xk(0<=Xk<=k-1,1<=k<=N) 输出 1行,表示最长上升子序列的长度是多少. 样例输入 3 0 0 2 样例输出 2 提示 100%的数据 n&l

PPT中实现长图片滚动条显示!(详解)

1.环境是ppt2010 2.点击开发工具. 3.如果没有开发工具 4.在属性里设置.

最长公共子序列 nlogn

先来个板子 #include<bits/stdc++.h> using namespace std; const int N = 1e6+20, M = 1e6+10, mod = 1e9+7, inf = 1e9+1000; typedef long long ll; struct node { int c; int num; } u[N]; int i,j,k = 0,n,m,x,y = 0,T = 0,ans = 0,big = 0,cas = 0,num = 0,len = 0; bo

POJ 2250 Compromise(最长公共子序列LCS)

http://poj.org/problem?id=2250 题意: 给你两段由空格分隔的语句, 要你求该两段语句的最长公共子序列. 且随便输出一个解即可. 注意每个单词需要看成我们一般处理字符串子序列的一个单独字符. 即每个单词是一个整体. 分析: 与往常计算最长公共子序列一样的方式即可. 然后用DFS输出序列即可.本题与POJ1458提供的解法本质一样. http://blog.csdn.net/u013480600/article/details/40741333 AC代码: #inclu

洛谷 [p1439] 最长公共子序列 (NlogN)

可以发现只有当两个序列中都没有重复元素时(1-n的排列)此种优化才是高效的,不然可能很不稳定. 求a[] 与b[]中的LCS 通过记录lis[i]表示a[i]在b[]中的位置,将LCS问题转化为最长上升子序列问题,转化方法如下: for(int i=1;i<=n;i++){ local[b[i]]=i; } for(int i=1;i<=n;i++){ lis[i]=local[a[i]]; } 当序列中有元素重复时,我们们需要保证对于每个a[i]所记录的位置必须是逆序的,以保证一个元素只取一

[ACM] 九度OJ 合唱队形 (最长递增子序列改版)

题目1131:合唱队形 时间限制:1 秒 内存限制:32 兆 特殊判题:否 提交:1680 解决:520 题目描述: N位同学站成一排,音乐老师要请其中的(N-K)位同学出列,使得剩下的K位同学不交换位置就能排成合唱队形. 合唱队形是指这样的一种队形:设K位同学从左到右依次编号为1, 2, -, K,他们的身高分别为T1, T2, -, TK, 则他们的身高满足T1 < T2 < - < Ti , Ti > Ti+1 > - > TK (1 <= i <=

TYVJ P1067 合唱队形 Label:上升子序列?

背景 NOIP2004 提高组 第三道 描述 N位同学站成一排,音乐老师要请其中的(N-K)位同学出列,使得剩下的K位同学排成合唱队形. 合唱队形是指这样的一种队形:设K位同学从左到右依次编号为1,2…,K,他们的身高分别为T1,T2,…,TK,  则他们的身高满足T1<...<Ti>Ti+1>…>TK(1<=i<=K). 你的任务是,已知所有N位同学的身高,计算最少需要几位同学出列,可以使得剩下的同学排成合唱队形. 输入格式 输入文件chorus.in的第一行是

合唱队形(动态规划)

Description N位同学站成一排,音乐老师要请其中的(N-K)位同学出列,使得剩下的K位同学排成合唱队形. 合唱队形是指这样的一种队形:设K位同学从左到右依次编号为1, 2, -, K,他们的身高分别为T1, T2, -, TK,则他们的身高满足T1 < T2 < - < Ti , Ti > Ti+1 > - > TK (1 <= i <= K). 你的任务是,已知所有N位同学的身高,计算最少需要几位同学出列,可以使得剩下的同学排成合唱队形. Inp