题目
题目描述: 赛时提示:保证出发点和终点都是空地
帕秋莉掌握了一种木属性魔法
这种魔法可以生成一片森林(类似于迷阵),但一次实验时,帕秋莉不小心将自己困入了森林
帕秋莉处于地图的左下角,出口在地图右上角,她只能够向上或者向右行走
现在给你森林的地图,保证可以到达出口,请问有多少种不同的方案
答案对2333取模
输入描述:
第一行两个整数m , n表示森林是m行n列
接下来m行,每行n个数,描述了地图
0 - 空地
1 - 树(无法通过)
一个整数表示答案
解析
这道题一看题型就能发现是dp。(我一开始还看成了是到终点的步数,我是瞎了吗)
- 我们知道,dp的基本操作就是递推!
所以我们只要知道了递推公式就完美了。
- 因为这道题题目也告诉了我们,我们只能往上面和右边走。
- 这么说不就是在告诉我们:当前点的方法数=下面点的方法数+左边节点的方法数。
- 总结出来递推公式就是dp[i][j] = dp[i+1][j] + dp[i][j - 1]。
那么操作就是:
- 先初始化地图数组(mp数组)。
- 将第一行和第一列设置为1作为递推的根(因为单纯按行或按列走只有一种情况)。
同时注意从起点向上和向右遇到了障碍就要停下来,因为我们没办法向下和左走,所以永远不可能到达。 - 然后从离起点最近的地方,一层一层的遍历完整个数组,我们就可以知道每个位置的可能数了。
- 最后把要的节点输出来就好了。
代码
#include <iostream> using namespace std; const int MOD = 2333; const int MAX = 3e3 + 7; //代码预处理 int mp[MAX][MAX], dp[MAX][MAX]; inline void read(int& res); int main() { int n, m; read(n); read(m); for (int i = 1; i <= n; i++) for (int j = 1; j <= m; j++) read(mp[i][j]); //初始化地图 for (int i = n; i >= 1; i--) if (mp[i][1]) break; else dp[i][1] = 1; //第1列初始化 for (int i = 1; i <= m; i++) if (mp[n][i]) break; else dp[n][i] = 1; //第n行初始化 for (int i = n - 1; i >= 1; i--) for (int j = 2; j <= m; j++) if (mp[i][j]) dp[i][j] = 0; else dp[i][j] = (dp[i + 1][j] + dp[i][j - 1]) % MOD; //可能数=行可能数+列可能数 cout << dp[1][m] << endl; return 0; } inline void read(int& res) { char c; int flag = 1; while ((c = getchar()) < '0' || c > '9') if (c == '-') flag = -1; res = c - '0'; while ((c = getchar()) >= '0' && c <= '9') res = res * 10 + c - '0'; res *= flag; }