牛客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]);//最终能到出口的走法数
}
最后,由分析得抓住以下公式便可以较好的解决该问题了。
到该格可走的路的条数=走到该格下方的条数+走到该格左方的条数
通过本题,令我对动态规划有了更深的理解,也将自己的理解分享给大家,若有不妥的地方,请大家指出,谢谢!