DAG上的动态规划

在讲述DGA前我们先来初步了解下动态规划的基础和核心。

我们从数字三角开始:

现在要求我们从顶点开始一直到底层的数字相加和最大。(每层选一个数)。我们可能会想,从每层中选出最大的不就好了吗?但结果,很显然出现了问题,就比如1~n-1层的数都比较小,突然在n层的时候出现一个特别大的数,前面取大数的结果就要全部推翻。又有人会想到,那就贪心吗?不行就回溯,直到找到最大的那个值,但你在想一下就会发现,一个n层的数字三角形完整的路线有2n-1,当n很大时,回溯法的速度太慢。但你有没有想到,让每一个数的位置上都存的是从这个点到n层的最大值呢?比如d[i]表示从i到n的最大距离。这样这个点就可以看成一个状态量,显示的是i层到n层的一种状态。有了这层关系,我们就可以得到它的递归公式:d(i,j)=本身的值+max(d(i+1,j),d(i+1,j+1));

经此你应该对什么是动态规划有了初步的了解,下面我们就来稍稍总结和继续加深:

动态规划的特点和性质:

  • 动态规划的核心就是状态和状态转移公式
  • 存在重叠子影响运算效率(记忆化搜素和递推可以解决)
  • 初始化尽量只用0和-1

重叠子解决方法一:递推

重叠子解决方法二: 记忆化搜素

现在我们就来将DAG了!

DAG是解决最短路,最长路或路径计数问题的一种常用方法,而在动态规划问题中很多的问题可以很巧妙的转化的DAG的问题上来。在DAG中也存在着两种存有区分的解决问题的模板。一种是任意起点和任意终点,另一种是指定起点和指定终点。好在两者互通性很强,理解起来也就没那么困难。

任意起点的最长路和字典序:

固定起点的最长路和最短路 ;

  先给出代码:

int dp(int s)
{
    if (vis[s])
        return d[s];//计算过的不用再计算了
    vis[s] = 1;
    int &ans = d[s];
    for (int i = 1; i <= n; i++)
        if (s >= v[i])
            ans = max(ans, dp(s - v[i]) + 1);//转移方程
    return ans;
}

这里的固定也就是说,只能从开始的位置一直查到底,不能向两边同时查找。dp和vis,v数组的初始化,用memset多可以解决。出来这种方法外,我们还可以用地推的形式来处理

for(int i=1;i<=n;i++)
    for (int j = v[i]; j <=ans; j++)//正序遍历
    {
        d[j] = max(d[j], d[j - v[i]] + 1);
    }
原文地址:https://www.cnblogs.com/7750-13/p/7358287.html