动态规划过程详解--传递信息求组合题目

Posted C_YCBX Py_YYDS

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了动态规划过程详解--传递信息求组合题目相关的知识,希望对你有一定的参考价值。

题目

在这里插入图片描述

oj平台

普通bfs或dfs暴力解法

此题在LeetCode上的难度显示是简单题,原因不言而喻,因为可以通过暴力解法通过。。。当然这种暴力解法一般只适用于问题规模30以下。。如果比赛中碰到大概率是1000以上复杂度。。。所以还是老老实实dp吧!

此题只要通过map把关系图建好,则就能通过暴力解法搜索

解题代码:

class Solution {
public:
    int numWays(int n, vector<vector<int>>& relation, int k) {
        unordered_map<int,vector<int>>check;
        //建表
        for(const auto t:relation){
            check[t[0]].emplace_back(t[1]);
        }
        queue<int>Q;   Q.push(0);
        int step = 1;
        int res = 0;
        //bfs搜索
        while(!Q.empty()){
            for(int i = Q.size();i>0;i--){
                const int t = Q.front();Q.pop();
                if(check.count(t)){
                vector<int>&q=check[t];
                for(const int pp:q){
                    if(step==k&&pp==n-1)
                        res++;
                    Q.push(pp);
                }
                }
            }
            step++;
            if(step>k)
                break;
        }
        return res;
    }
};

dp过程详解

动态规划的过程一般模块化的分为以下几步:

  1. 读题找出相关联的状态,并根据状态得出具体的dp数组实例。
  2. 通过dp数组状态间的联系建立dp数组的状态转移方程。
  3. 通过完成基本案例的填写,base case填好后,根据状态转移方程确定遍历方向。

下面就对上述过程进行实践

  1. 找出相关联的状态:传递的次数 和 到达的编号,列出 dp[i][j] :表示传递了i次后到达j的方案数。
  2. 根据dp数组含义建立动态转移方程:dp[i][j] = dp[i-1][k1..kn](其中k1到kn表示能传到j的上一次编号)
  3. 填写 base case:dp[0][0] = 1 其余初始值均为0。则遍历方向可以是自由横向方向(毕竟只依赖上一行数据,而第0行都已经确定了答案)。

不优化的二维dp数组解法

class Solution {
public:
    int numWays(int n, vector<vector<int>>& relation, int k) {
        int dp[k+1][n];memset(dp,0,sizeof(dp));
        dp[0][0] = 1;
        for(int i = 1;i<=k;i++){
            for(const auto t:relation){
                dp[i][t[1]] += dp[i-1][t[0]];
            }
        }
        return dp[k][n-1];
    }
};

优化为一维数组

由于每次的答案只和上一行的结果相关,由于横向遍历无法控制方向,所以直接建立临时数组保存下一行的答案,然后再与dp不断替换来实现一维数组优化。

class Solution {
public:
    int numWays(int n, vector<vector<int>>& relation, int k) {
        int*dp = (int*)malloc(sizeof(int)*n);
        memset(dp,0,n*sizeof(int));
        dp[0] = 1;
        for(int i = 1;i<=k;i++){
            //申请动态数组记录一行的结果
            int*tmp = (int*)malloc(sizeof(int)*n);
            memset(tmp,0,n*sizeof(int));
            for(const auto t:relation){
                tmp[t[1]] += dp[t[0]];
            }
            free(dp);
            dp = tmp;
        }
        return dp[n-1];
    }
};

以上是关于动态规划过程详解--传递信息求组合题目的主要内容,如果未能解决你的问题,请参考以下文章

动态规划的题目特点以及求“硬币个数最少”

动态规划——详解leetcode518 零钱兑换 II

0x52. 动态规划 - 背包(习题详解 × 19)

由Leetcode详解算法 之 动态规划(DP)

动态规划详解

LeetCode刷题笔记-动态规划-day7