dp学习笔记2

动态规划的思想有时候很难体会,我觉得debug是一件很有帮助的事情。。。

 
View Code
 1 /*
 2 N位同学站成一排,音乐老师要请其中的(N-K)位同学出列,使得剩下的K位同学排成合唱队形。
 3 合唱队形是指这样的一种队形:设K位同学从左到右依次编号为1,2…,K,
 4 他们的身高分别为T1,T2,…,TK,  则他们的身高满足T1<...<Ti>Ti+1>…>TK(1<=i<=K)。
 5 你的任务是,已知所有N位同学的身高,计算最少需要几位同学出列,可以使得剩下的同学排成合唱队形。
 6 */
 7 /*
 8 样例输入:
 9 8
10 186 186 150 200 160 130 197 220
11 样例输出:
12 4
13 */
14 /*
15 分析:
16 出列人数最少,也就是说留的人最多,也就是序列最长。
17 这样分析就是典型的最长下降子序列问题。
18 只要枚举每一个人站中间时可以的到的最优解。显然它就等于,包括他在内向左求最长上升子序列,向右求最长下降子序列。
19 其实最长子序列只要一次就可以了。因为最长下降(上升)子序列不受中间人的影响。
20 只要用dp1求一次最长上升子序列,dp2求一次最长下降子序列。这样答案就是N-max(opt1[i]+opt2[i]-1).(减1是由于最后一个在上升中算了,又在下降中算了,共算了2次)
21 */
22 
23 #include<iostream>
24 using namespace std;
25 int h[100];
26 int dp1[100];
27 int dp2[100];
28 
29 int main(){
30     int n;
31     while(~scanf("%d",&n)){
32         for(int i=1;i<=n;i++){
33             scanf("%d",&h[i]);
34         }
35         memset(dp1,0,sizeof(dp1));
36         memset(dp2,0,sizeof(dp2));
37         //求最长下降子序列
38         for(int i=1;i<=n;i++){
39             int ans=0;
40             for(int j=0;j<i;j++){
41                 if(h[i]<h[j]&&dp1[j]>ans){
42                     ans=dp1[j];
43                 }
44             }
45             dp1[i]=ans+1;//自己本身
46         }
47         //求最长上升子序列
48         for(int i=1;i<=n;i++){
49             int ans=0;
50             for(int j=0;j<i;j++){
51                 if(h[i]>h[j]&&dp2[j]>ans){
52                     ans=dp2[j];
53                 }
54             }
55             dp2[i]=ans+1;
56         }
57         int ans=0;
58         for(int i=1;i<=n;i++){
59             ans=max(ans,dp1[i]+dp2[i]-1);
60         }
61         printf("%d\n",n-ans);
62     }
63     return 0;
64 }

 

posted @ 2013-03-25 21:55  ihge2k  阅读(269)  评论(0编辑  收藏  举报