牛客NC53675(动态规划)

牛客NC53675(动态规划)

动态规划

动态规划(Dynamic Programming)是一种解决多阶段决策问题的优化方法。它将原问题划分为多个子问题,并通过递推关系来求解子问题的解,从而最终求解原问题。

动态规划的思想基于两个关键要素:最优子结构重叠子问题

最优子结构

原问题的最优解可以通过一系列问题的最优解来递归地求解。

也就是原问题的最优解必然包含了子问题的最优解。

通过求子问题的最优解,从而得到原问题的最优解。

重叠子问题

子问题之间存在重叠,即不同的子问题可能会多次计算相同的子问题。

动态规划通过将子问题的解存储起来(一般是利用数组或哈希表),避免重复计算子问题,提高运行效率。

题解

分解问题

首先我们要进行分析,从左下角到右上角有多少条路可走。

我们先不管有树丛的情况,假设不存在树丛,以3×3的大小的地图举例。

在这里插入图片描述

这时我们要是一个一个来数有多少条路可走的话,会很麻烦,并且容易多数或者少数。

这是我们就可以思索一下是不是可以将问题分解。

那我们就想到先看2×2的地图有多少条路可走。

在这里插入图片描述

如图我们就可以分析出2×2的地图有2条路可走。

同时我们也找到一个规律:

到该格可走的路的条数=走到该格下方的条数+走到该格左方的条数

!!!

如此再来看3×3的地图

在这里插入图片描述

由此再加上有树丛的情况,以题目的样例为例子。

在这里插入图片描述

令阴影网格为小树丛。

得到该样例最终能有3种走法走到出口。

代码

#include<stdio.h>
#include<stdlib.h>
long long dp[3050][3050];//存储走法
int a[3050][3050];//存储地图
int main()
{
    int m, n, i, j;
    scanf("%d%d", &n, &m);
    for (i = 1; i <= n; i++)
        for (j = 1; j <= m; j++)
            scanf("%d", &a[i][j]);
    dp[n][1] = 1;
    for (i = n; i >= 1; i--)
    {
        for (j = 1; j <= m; j++)
        {
            if (a[i][j] != 1)//判断自身是否为小树丛
            {
                if (i + 1 <= n)//判断下方是否越界,若不越界,将能走到下方网格的走法加上
                    dp[i][j] = (dp[i][j] + dp[i + 1][j]) % 2333;
                if (j - 1 >= 1)//判断左方是否越界,若不越界,将能走到左方网格的走法加上
                    dp[i][j] = (dp[i][j] + dp[i][j - 1]) % 2333;
            }
            else//若为小树丛则能到该格的走法为0
                dp[i][j] = 0;
        }
    }
    printf("%lld\n", dp[1][m]);//最终能到出口的走法数
}

最后,由分析得抓住以下公式便可以较好的解决该问题了。

到该格可走的路的条数=走到该格下方的条数+走到该格左方的条数

通过本题,令我对动态规划有了更深的理解,也将自己的理解分享给大家,若有不妥的地方,请大家指出,谢谢!

参考文章:https://blog.csdn.net/qq_37771475/article/details/126855564?ops_request_misc=&request_id=&biz_id=102&utm_term=%E5%8A%A8%E6%80%81%E8%A7%84%E5%88%92&utm_medium=distribute.pc_search_result.none-task-blog-2allsobaiduweb~default-0-126855564.142v91insertT0,239v3insert_chatgpt&spm=1018.2226.3001.4187

题目来源:https://ac.nowcoder.com/acm/problem/53675

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值