[dp] 小信走迷宫

题目描述

小信又在迷宫中迷路了,这是一个 N × M N \times M N×M 的迷宫。迷宫里有一些障碍物,用 # 表示,能正常通过的格子用 . 表示。小信现在位于迷宫左上角 ( 1 , 1 ) (1, 1) (1,1) 的位置。

由于小信拥有超人的魔力,当他在位置 ( x , y ) (x, y) (x,y) 时,可以执行以下操作:

  • 向右移动任意个单位(不能穿过障碍物),不能移出迷宫,即移动到位置 ( x , y + k ) { 1 ≤ k , y + k ≤ M } (x, y + k)\{1 \le k, y + k \le M\} (x,y+k){1≤k,y+k≤M}。
  • 向下移动任意个单位(不能穿过障碍物),不能移出迷宫,即移动到位置 ( x + k , y ) { 1 ≤ k , x + k ≤ N } (x + k, y)\{1 \le k, x + k \le N\} (x+k,y){1≤k,x+k≤N}。
  • 沿着当前位置的对角线向右下移动任意个单位(不能穿过障碍物),但必须在迷宫范围内,即移动到位置 ( x + k , y + k ) { 1 ≤ k ≤ min ⁡ ( n , m ) , 1 ≤ x + k ≤ N , 1 ≤ y + k ≤ M } (x + k, y + k)\{1 \le k \le \min(n, m), 1 \le x + k \le N, 1 \le y + k \le M\} (x+k,y+k){1≤k≤min(n,m),1≤x+k≤N,1≤y+k≤M}。

现在他想知道从他当前的位置 ( 1 , 1 ) (1, 1) (1,1) 走到右下角 ( N , M ) (N, M) (N,M)有多少种方案数,答案对 998244353 998244353 998244353 取模。

输入格式

第一行输入两个正整数 N N N 和 M M M,表示迷宫的行数和列数。

接下来 N N N 行,每行 M M M 个字符数,表示有无障碍物。

输出格式

输出一个正整数,表示总共有多少方案数。

样例

样例输入1:

3 3
...
.#.
...

样例输出1:

10

样例解释1:

对于样例1,有如下10种方法:

  • ( 1 , 1 ) → ( 1 , 2 ) → ( 1 , 3 ) → ( 2 , 3 ) → ( 3 , 3 ) (1, 1) \to (1, 2) \to (1, 3) \to (2, 3) \to (3, 3) (1,1)→(1,2)→(1,3)→(2,3)→(3,3)
  • ( 1 , 1 ) → ( 1 , 2 ) → ( 1 , 3 ) → ( 3 , 3 ) (1, 1) \to (1, 2) \to (1, 3) \to (3, 3) (1,1)→(1,2)→(1,3)→(3,3)
  • ( 1 , 1 ) → ( 1 , 2 ) → ( 2 , 3 ) → ( 3 , 3 ) (1, 1) \to (1, 2) \to (2, 3) \to (3, 3) (1,1)→(1,2)→(2,3)→(3,3)
  • ( 1 , 1 ) → ( 1 , 3 ) → ( 2 , 3 ) → ( 3 , 3 ) (1, 1) \to (1, 3) \to (2, 3) \to (3, 3) (1,1)→(1,3)→(2,3)→(3,3)
  • ( 1 , 1 ) → ( 1 , 3 ) → ( 3 , 3 ) (1, 1) \to (1, 3) \to (3, 3) (1,1)→(1,3)→(3,3)
  • ( 1 , 1 ) → ( 2 , 1 ) → ( 3 , 1 ) → ( 3 , 2 ) → ( 3 , 3 ) (1, 1) \to (2, 1) \to (3, 1) \to (3, 2) \to (3, 3) (1,1)→(2,1)→(3,1)→(3,2)→(3,3)
  • ( 1 , 1 ) → ( 2 , 1 ) → ( 3 , 1 ) → ( 3 , 3 ) (1, 1) \to (2, 1) \to (3, 1) \to (3, 3) (1,1)→(2,1)→(3,1)→(3,3)
  • ( 1 , 1 ) → ( 2 , 1 ) → ( 3 , 2 ) → ( 3 , 3 ) (1, 1) \to (2, 1) \to(3, 2) \to (3, 3) (1,1)→(2,1)→(3,2)→(3,3)
  • ( 1 , 1 ) → ( 3 , 1 ) → ( 3 , 2 ) → ( 3 , 3 ) (1, 1) \to (3, 1) \to (3, 2) \to(3, 3) (1,1)→(3,1)→(3,2)→(3,3)
  • ( 1 , 1 ) → ( 3 , 1 ) → ( 3 , 3 (1, 1) \to (3, 1) \to (3, 3 (1,1)→(3,1)→(3,3)

样例输入2:

4 4
...#
....
..#.
....

样例输出2:

84

样例输入3:

8 10
..........
..........
..........
..........
..........
..........
..........
..........

样例输出3:

13701937

数据范围

对于 10 % 10\% 10% 的数据, 2 ≤ N , M ≤ 4 2 \le N, M \le 4 2≤N,M≤4。

对于 20 % 20\% 20% 的数据, 2 ≤ N , M ≤ 10 2 \le N, M \le 10 2≤N,M≤10。

对于 50 % 50\% 50% 的数据, 2 ≤ N , M ≤ 100 2 \le N, M \le 100 2≤N,M≤100。

对于 100 % 100\% 100% 的数据, 2 ≤ N , M ≤ 2000 2 \le N, M \le 2000 2≤N,M≤2000。

数据保证起点 ( 1 , 1 ) (1, 1) (1,1) 和终点 ( N , M ) (N, M) (N,M) 是 .

题解

1

考虑使用 dp 算法。

设 d p i , j dp_{i, j} dpi,j 表示到 ( i , j ) (i, j) (i,j) 的位置的方案数。

状态转移:

  • 如果 a i , j a_{i, j} ai,j 等于 #

说明有障碍物,不能走, d p i , j = 0 dp_{i, j} = 0 dpi,j=0。

  • 如果 a i , j a_{i, j} ai,j 等于 .
  1. 向下转移: ∑ x ≤ k < i ∀ k a k , j = . d p k , j ( 1 ≤ x ) \sum_{x \le k < i}^{\forall{k}\ a_{k, j} = .}dp_{k,j}(1 \le x) x≤k<i∑∀k ak,j=.dpk,j(1≤x)
    即从 i i i 开始向前,一直到 a k , j a_{k, j} ak,j 是 . 为止,并把 d p k , j dp_{k, j} dpk,j 加在 d p i , j dp_{i, j} dpi,j 里面。
cpp 复制代码
for(int k = i; k >= 1; -- k){
	if(a[k][j] == '#')	break;
	dp[i][j] += dp[k][j];
}

复杂度 O ( i ) \Omicron(i) O(i),近似 Θ ( N ) \Theta(N) Θ(N)。
2. 向右转移: ∑ x ≤ k < j ∀ k a i , k = . d p i , k ( 1 ≤ x ) \sum_{x \le k < j}^{\forall{k}\ a_{i, k} = .}dp_{i, k}(1 \le x) x≤k<j∑∀k ai,k=.dpi,k(1≤x)
即从 j j j 开始向前,一直到 a i , k a_{i, k} ai,k 是 . 为止,并把 d p i , k dp_{i, k} dpi,k 加在 d p i , j dp_{i, j} dpi,j 里面。

cpp 复制代码
for(int k = j; k >= 1; -- k){
	if(a[i][k] == '#')	break;
	dp[i][j] += dp[i][k];
}

复杂度 O ( j ) \Omicron(j) O(j),近似 Θ ( M ) \Theta(M) Θ(M)。
3. 向右下转移: ∑ x ≤ k < min ⁡ ( i , j ) ∀ a i − k , j − k = . ( 1 ≤ x ) \sum_{x \le k < \min(i, j)}^{\forall\ a_{i - k, j - k} = .}(1 \le x) x≤k<min(i,j)∑∀ ai−k,j−k=.(1≤x)
即从 i , j i, j i,j 开始向前,一直到 a i − k , j − k a_{i - k, j - k} ai−k,j−k 是 . 为止,并把 d p i − k , j − k dp_{i - k, j - k} dpi−k,j−k 加在 d p i , j dp_{i, j} dpi,j 里面。

cpp 复制代码
for(int k = 1; k < min(j, k); ++ k){
	if(a[i - k][j - k] == '#')	break;
	dp[i][j] += dp[i - k][j - k];
}

复杂度 O ( min ⁡ ( i , j ) ) \Omicron(\min(i, j)) O(min(i,j)),,近似 Θ ( min ⁡ ( N , M ) ) \Theta(\min(N, M)) Θ(min(N,M))。

综上,我们就得出了 d p i , j dp_{i, j} dpi,j 的转移方程,时间复杂度近似 Θ ( 3 × K ) ( K = max ⁡ ( N , M ) ) \Theta(3 \times K)(K = \max(N, M)) Θ(3×K)(K=max(N,M))。

答案就是走到 ( N , M ) (N, M) (N,M) 的方案数,即 d p N , M dp_{N, M} dpN,M。

还要加上取模。

复杂度为 Θ ( N × M × K ) ( K = max ⁡ ( N , M ) ) \Theta(N \times M \times K)(K = \max(N, M)) Θ(N×M×K)(K=max(N,M)),会超时,能得 60 % 60\% 60% 的分数。

2

由于累加的值都是在一条直线上连续的值,考虑使用前缀和进行优化。

用 d p 0 / 1 / 2 , i , j dp_{0/1/2, i, j} dp0/1/2,i,j 分别表示横,纵,斜三个方向上到 ( i , j ) (i, j) (i,j) 的转移, d p 3 , i , j dp_{3, i, j} dp3,i,j 表示到 ( i , j ) (i, j) (i,j) 的方案数。

以横向为例。

如果 ( i , j ) (i, j) (i,j) 是 #,则清空前缀和( d p 0 , i , j ← 0 dp_{0, i, j} \gets 0 dp0,i,j←0)。

如果 ( i , j ) (i, j) (i,j) 是 .,则加上 d p 3 , i − 1 , j dp_{3, i - 1, j} dp3,i−1,j。(它既可以从前面转移,也可以从 ( i − 1 , j ) (i - 1, j) (i−1,j) 转移)。

复杂度为 Θ ( N × M ) \Theta(N \times M) Θ(N×M)。

cpp 复制代码
输入
for(int i = 1; i <= n; ++ i){
	for(int j = 1; j <= n; ++ j){
		if(i == 1 && j == 1){
			//初始化,最开始在 (1, 1),方案为 1
			dp[3][i][j] = 1; 
			continue;
		}
		if(a[i][j] == '#'){
			dp[0][i][j] = dp[1][i][j] = dp[2][i][j] = dp[3][i][j] = 0;
			continue;
		}
		//横
		dp[1][i][j] = (dp[1][i - 1][j] + dp[0][i - 1][j]) % mod;
		//纵
		dp[2][i][j] = (dp[2][i][j - 1] + dp[0][i][j - 1]) % mod;
		//斜
		dp[3][i][j] = (dp[3][i - 1][j - 1] + dp[0][i - 1][j - 1]) % mod;
		//总方案数
		dp[0][i][j] = ((dp[1][i][j] + dp[2][i][j]) % mod + dp[3][i][j]) % mod;
	}
}
输出 dp[0][n][m]
相关推荐
捕鲸叉14 分钟前
创建线程时传递参数给线程
开发语言·c++·算法
A charmer18 分钟前
【C++】vector 类深度解析:探索动态数组的奥秘
开发语言·c++·算法
wheeldown1 小时前
【数据结构】选择排序
数据结构·算法·排序算法
观音山保我别报错2 小时前
C语言扫雷小游戏
c语言·开发语言·算法
TangKenny3 小时前
计算网络信号
java·算法·华为
景鹤3 小时前
【算法】递归+深搜:814.二叉树剪枝
算法
iiFrankie3 小时前
SCNU习题 总结与复习
算法
Dola_Pan4 小时前
C++算法和竞赛:哈希算法、动态规划DP算法、贪心算法、博弈算法
c++·算法·哈希算法
小林熬夜学编程4 小时前
【Linux系统编程】第四十一弹---线程深度解析:从地址空间到多线程实践
linux·c语言·开发语言·c++·算法
阿洵Rain5 小时前
【C++】哈希
数据结构·c++·算法·list·哈希算法