代码改变世界

动态规划第一题

2013-02-16 11:18  Dr.Ray  阅读(190)  评论(0)    收藏  举报

           找一个无序数列中最长的非降序子数列。

           此题目中,状态为一维的。

           证明这个题目可以用动态规划解决,即证明满足最优性原理(即具有最有子结构)和无后效性。

           证明满足最优性原理:

           这一块我目前还不太清晰,试着说明。序列记为{an}

           对于前i-1个数,最长非降序子序列用到ak,长度为c,那么加入ai后长度为c+1或c,则前i 个数中最长子序列长度还是c或c+1

           对于前k-1个数,同上。

           于是,在前j个数中,最长子序列长度为q,那么q或q-1为前j-1个数的最长非降序子序列长度,满足最有型原理。

 

           证明满足无后效性:

           明显第i个状态只用考虑前i-1个数,遂无后效性。

 

三要素:

阶段:

      按序列角标划分阶段。

状态:

      开数组opt[i]储存每个阶段的最长子序列长度。

策略:

      找到前i-1中满足ak<=ai且opt[k]最大的一项,使得opt[i]=opt[k]+1;

 

代码:

#include<stdio.h> #include<stdlib.h> #include<string.h>

 

int main() {     int a[]={2,3,15,16,16,9,5,22,1,17};     int opt[10];     memset(opt, 0, sizeof(opt));     int ans = -1;     for(int i=0; i<10; i++)     {         if(i==0)         {             opt[i] = 1;         }         for(int j=0; j<i; j++)         {             if(a[j]<=a[i] && opt[j]+1>opt[i])             {                 opt[i] = opt[j]+1;             }         }     }     for(int i=0; i<10; i++)     {         if(opt[i]>ans)         {             ans = opt[i];         }     }     printf("%d\n",ans); }

 

最大的问题出现在如何找到opt[k]最大且ak<=ai,一开始的想法是找到opt[k]最大项,记录k,然后如果不满足ak<=ai那么重新找次大的opt[k],很麻烦。

题解是把前i-1项遍历,寻找满足(a[j]>a[i]&&opt[j]+1>opt[i])的项,于是最后得到满足要求。

     可知,当目标元素不容易确定时,把每项都当做目标元素遍历一遍储存到目标状态中,并用目标状态做限定条件,遍历完就能达到目的without知道目标元素的位置。