这几天相当煎熬,动态规划实在是太难了,感觉最难的就是抽象递归,和贪心stl不同,dp代码的关键位置是看不懂的,看十几遍也整不动,以前最起码可以根据代码理清思路,现在只有将代码实现过程写到纸上手动跑才能勉强搞懂。
          一个最长上升子段和问题,整整一天,在纸上写了一遍又一遍才把递归过程搞懂,现在说一下具体过程。
          问题不再赘述,直接举例,给一个数列如下
                      1   7   2   8   3   4  
那么它的最长上升子序列就是
                      1   2   3   4 
长度为4,所以这个数列的最长子序列长度就是4。
         现在来展示最核心的递归过程(图片出自知乎Mingqi)

动态规划阶段性学习总结
         这里我们可以看到,LIS(K+1)要么等于LIS(K),要么加了一。其实也很好理解,基本上就是,在前面所有的LIS种找到一个最长的LIS(i),如果A(K)比这个找到LIS(i)的尾项A(i)要大,则LIS(K)=LIS(i)+1,否则LIS(K)=LIS(i)。
           代码实现如下
#include <iostream>
using namespace std;
int a[10001],maxlen[10001];
int main()
{
    int n;
    cin>>n;
    for(int i = 1;i<=n;i++)
        cin>>a[i];
    maxlen[1] = 1;
    for(int i = 2;i<=n;i++)
    {
        int temp = 0;//记录最长子序列的最后一个元素
        for(int j = 1;j<i;j++)
        //遍历i之前的所有元素,如果i大于j,那么子序列累加
        {
            if(a[i]>a[j])
            {
                if(maxlen[j]>temp)
                    temp = maxlen[j];
            }
        }
        maxlen[i] = temp+1;
        //加1是包含a[i]本身
    }
    int amax = -1;
    for(int i = 1;i<=n;i++)
        amax = max(amax,maxlen[i]);
    cout<<amax<<endl;
    return 0;
}
        由这道题可以看出,dp最关键的就是递归的形式,也就是状态转移,一旦搞懂,豁然开朗!
        即使越学越绝望也不能放弃,就要和dp肝到底,一天整不懂就两天,一道题不行就两道三道,积累量变,总能质变。

相关文章: