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

题目

在这里插入图片描述

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];
    }
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值