zoukankan      html  css  js  c++  java
  • 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);
        }
  • 相关阅读:
    JS函数强化
    Javascript创建对象的方式
    call和apply的区别
    事件绑定和普通事件有什么区别
    又走一个
    风的季节
    关于Dictionary的线程安全问题
    进程管理简述
    开通
    WPF 音乐播放器界面
  • 原文地址:https://www.cnblogs.com/7750-13/p/7358287.html
Copyright © 2011-2022 走看看