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 }