关于动态规划(入门篇)

题记:网上DP总结如云……

但较于杂乱,对新手的入门无层次渐进的指导,故写此篇。

 

动态规划的启蒙题目

题目:Pku 1163 the Triangle http://acm.pku.edu.cn/JudgeOnline/problem?id=1163

      HDU 2084 数塔 http://acm.hdu.edu.cn/showproblem.php?pid=2084

对于一个有数字组成的二叉树,求由叶子到根的一条路径,使数字和最大,如:


这个是经典的动态规划,也是最基础、最简单的动态规划,典型的多段图。思路就是建立一个数组,由下向上动态规划,保存页子节点到当前节点的最大值

核心代码:(c语言)

for (i=n-2;i>=0;i--)

{

    for (j=0;j<=i;j++)

    {

        a[i][j] += a[i+1][j]>a[i+1][j+1]?a[i+1][j]:a[i+1][j+1];

    }

}

本题的详细完整代码请浏览:

http://blog.csdn.net/jqandjq/archive/2009/02/26/3938367.aspx

 

此题的特点是可以用递归的方法,但那为了避免重复地搜索,往往会运用“记录递归”的方法,那是一种自顶向下的过程,而DP的方法则相反,是一种自底向上逐步保存过程,用数组保存模拟。

由此我们可以推广出一种DP用“记录递归”的方法来完成:

 

Pku 1579 Function Run Fun  http://acm.pku.edu.cn/JudgeOnline/problem?id=1579

Hdu 1579 Function Run Fun  http://acm.hdu.edu.cn/showproblem.php?pid=1579

这本身就是一个递归函数,要是按照函数本身写递归式,结果肯定是TLE,这里我开了一个三维数组,从w(0,0,0)开始递推,逐步产生到w(20,20,20)的值,复杂度O(n^3).

总结:这道题是很地道的DP,因为它的子问题实在是太多了,所以将问题的结果保存起来,刘汝佳《算法艺术和信息学竞赛》中115页讲到自底向上的递推,这个例子就非常典型。总体来说这个题目还是非常简单的,不过这个思想是地道的动态规划。

本题的详细完整代码请浏览:

http://blog.csdn.net/jqandjq/archive/2009/02/26/3938504.aspx

 

接下来的介绍有关于动态规划的几种基础类型:

1.求序列的连续最大段 à 推广类型:求矩阵的最大子矩阵

2.求序列的最大上升序列

3.求序列的最大连续上升子序列

 

求序列的连续最大段:

典型例题:Max Sum:http://acm.hdu.edu.cn/showproblem.php?pid=1003

这是DP的经典之一,欲求出一个最优的结果,但不暴力地去枚举。

如一个序列:6,-1,5,4,-7 求它的连续最大段就是:6 + (-1) + 5 + 4 = 14.

用DP的方法只要一重的循环就可以把这道题搞定:

每一次的计算对前一次结果不会有影响,这是DP的特点。

这样之要从第一个开始计算,6 -1 5 4 -7 的最大值分别是 6 5 10 14 7

如果计算过程中值出现小于零的情况那就将值归零。

核心C代码:

        int sum=0,maxnum=-1001,first =0, last = 0, temp = 1;

        for (i=0;i<n;i++)

        {

            sum += a[i];

            if (sum > maxnum)

            {

                maxnum = sum;first = temp;last = i+1;

            }

            if (sum < 0)

            {

                sum = 0;temp = i+2;

            }

        }

本题的详细完整代码请浏览:

http://blog.csdn.net/jqandjq/archive/2009/02/26/3940608.aspx

 

下面看一下上一题的推广类型:

求矩阵的最大子矩阵

典型例题:

Pku 1050 To The Max  http://acm.pku.edu.cn/JudgeOnline/problem?id=1050

Hdu 1081 To The Max  http://acm.hdu.edu.cn/showproblem.php?pid=1081

 

题目的意思很简单,在一个矩阵里面找它的子矩阵,使得子矩阵数值之和到达最大。其实就是最大子段和问题在二维空间上的推广。考察下面题目中的例子:

0  -2  -7  0

9   2  -6  2

-4  1  -4  7

-1  8   0 -2

我们分别用i j表示起始行和终止行,遍历所有的可能:

for(i=1;i<=n;i++)

    for(j=i;j<=n;j++) {}

我们考察其中一种情况 i=2 j=4,这样就相当与选中了2 3 4三行,求那几列的组合能获得最大值,由于总是 2 3 4行,所以我们可以将这3行”捆绑”起来,变为求 4(9-4-1),11(8+2+1),-10(-6-4+0),7(7+2-2)的最大子段和,ok,问题成功转化为一维的情况!

核心代码:

for (i=0;i<n;i++)

        {

            for (j=0;j<n;j++)

            {

                if (i == j) //只有一行的情况,我们只单纯地抽取这行

                {

                    for (k=0;k<n;k++)

                    {

                        b[k] = a[i][k];

                    }

                }

                else //如果有多行,那么捆绑每一列的和,使之成为一行

                {

                    for (k=0;k<n;k++)

                    {

                        b[k] = 0;

                        for (l=i;l<=j;l++)

                        {

                            b[k] += a[l][k];

                        }

                    }

                }

            //这里直接用求求序列的连续最大段就OK了。

            }

        }

本题的详细完整代码请浏览:

http://blog.csdn.net/jqandjq/archive/2009/02/26/3940653.aspx

 

求序列的最大上升序列:

经典例题:HDU 1087 Super Jumping! Jumping! Jumping!

http://acm.hdu.edu.cn/showproblem.php?pid=1087

这道理的题意是给一个序列要你求它的最大上升序列(可跳)不用连续

如序列:1 4 7 3 5 6 那么开另一个数组来保存同下标的“最大值”,每一个都要向前找合法的最大b值,如这里的5可以找的合法值为3 4 1,找到最大后便加上同下标的a值,如:

数组a:1   4   7   3   5   6

数组b:1   5  12   4  10  16  à这样找到B中的最大值就OK了!

核心代码:

for (i=0;i<n;i++)

              {

                     b[i] = a[i];

                     int maxb = 0;

                     for (j=0;j<i;j++)      //找比自己小的里面b最大的

                     {

                            if (a[i] > a[j])

                            {

                                   if (b[j] > maxb)

                                   {

                                          maxb = b[j];

                                   }

                            }

                     }

                     b[i] += maxb;

                     if (b[i] > maxnum)

                     {

                            maxnum = b[i];

                     }

              }

本题的详细完整代码请浏览:

http://blog.csdn.net/jqandjq/archive/2009/02/26/3940712.aspx

 

本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/jqandjq/archive/2009/12/23/5060283.aspx

你可能感兴趣的:(c,算法,function,ini,语言,fun)