zoukankan      html  css  js  c++  java
  • 【dp】合唱队形

    例题二 

    合唱队形

    (chorus.pas/c/cpp)

    来源:NOIP2004(提高组) 第一题

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

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

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

    【输入文件】

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

    【输出文件】

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

    【样例输入】

    8

    186 186 150 200 160 130 197 220

    【样例输出】

    4

    【数据规模】

    对于50%的数据,保证有n<=20;

    对于全部的数据,保证有n<=100。

    【问题分析】

      出列人数最少,也就是说留的人最多,也就是序列最长。

    这样分析就是典型的最长下降子序列问题。只要枚举每一个人站中间时可以的到的最优解。显然它就等于,包括他在内向左求最长上升子序列,向右求最长下降子序列。

    我们看一下复杂度:

    计算最长下降子序列的复杂度是O(N2),一共求N次,总复杂度是O(N3)。这样的复杂度对于这个题的数据范围来说是可以AC的。但有没有更好的方法呢?

    其实最长子序列只要一次就可以了。因为最长下降(上升)子序列不受中间人的影响。

    只要用OPT1求一次最长上升子序列,OPT2求一次最长下降子序列。这样答案就是N-max(opt1[i]+opt2[i]-1).

     复杂度由O(N3)降到了O(N2)。

     

     1 #include<iostream>
     2 #include<algorithm>
     3 #include<string>
     4 #include<vector>
     5 #include<set>
     6 #include<queue>
     7 #include<map>
     8 #include<stack>
     9 #include<iterator>
    10 #include<cstdio>
    11 #include<cstring>
    12 #include<cstdlib>
    13 #include<cmath>
    14 using namespace std;
    15 typedef long long ll;
    16 typedef unsigned long long ull;
    17 #define clr(c) memset(c, 0, sizeof(c));
    18 #define pi acos(-1.0)
    19 const int INF = 0x3f3f3f3f;
    20 const int mod = 1e9 + 7;
    21 const double eps = 1e-8;
    22 typedef struct point{
    23     int x, y;
    24     bool operator < (const point& p) const{
    25         if (x == p.x) return y < p.y;
    26         else return x < p.x;
    27     }
    28     bool operator >(const point& p) const{
    29         return p < *this;
    30     }
    31 }p;
    32 
    33 int a[105], n;
    34 int dp1[105];
    35 int dp2[105];
    36 
    37 int main(){
    38     while(~scanf("%d", &n)){
    39         for(int i = 0; i < n; i++) scanf("%d", &a[i]);
    40 
    41         for(int i = 0; i < n; i++) dp1[i] = 1;
    42         for(int i = 1; i < n; i++){
    43             for(int j = 0; j < i; j++){
    44                 if(a[i] > a[j] && dp1[j]+1 > dp1[i]) dp1[i] = dp1[j]+1;
    45             }
    46         }
    47 
    48         for(int i = 0; i < n; i++) dp2[i] = 0;
    49         for(int i = n-1; i >= 0; i--){
    50             for(int j = i; j < n; j++){
    51                 if(a[i] > a[j] && dp2[j]+1 > dp2[i]) dp2[i] = dp2[j]+1;
    52             }
    53         }
    54 
    55         int ans = 0;
    56         for(int i = 0; i < n; i++){
    57             if(ans < dp1[i]+dp2[i]) ans = dp1[i]+dp2[i];
    58         }
    59 
    60         //for(int i = 0; i < n; i++) printf("%d ", dp1[i]); printf("
    ");
    61         //for(int i = 0; i < n; i++) printf("%d ", dp2[i]); printf("
    ");
    62         printf("%d
    ", ans);
    63     }
    64 
    65     return 0;
    66 }
  • 相关阅读:
    DWR3.0 如何应用的简单介绍(有实例)
    细线表格样式
    myeclipse不编译解决方法
    DORADO中resoler&dataProvider的常用方法
    jBPM插件下载地址及jBPM配置视频
    dorado要点总结
    千万级数据库(MSSQL)删除重复记录
    Dorado 7 IDE下载地址
    WIN CE和电脑之间的文件拷贝(2) Form1.cs文件
    获取所有存储过程源码替换存储过程方法
  • 原文地址:https://www.cnblogs.com/miaowTracy/p/5929058.html
Copyright © 2011-2022 走看看