[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){1k,y+kM}
  • 向下移动任意个单位(不能穿过障碍物),不能移出迷宫,即移动到位置 ( x + k , y ) { 1 ≤ k , x + k ≤ N } (x + k, y)\{1 \le k, x + k \le N\} (x+k,y){1k,x+kN}
  • 沿着当前位置的对角线向右下移动任意个单位(不能穿过障碍物),但必须在迷宫范围内,即移动到位置 ( 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){1kmin(n,m),1x+kN,1y+kM}

现在他想知道从他当前的位置 ( 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 2N,M4
对于 20 % 20\% 20% 的数据, 2 ≤ N , M ≤ 10 2 \le N, M \le 10 2N,M10
对于 50 % 50\% 50% 的数据, 2 ≤ N , M ≤ 100 2 \le N, M \le 100 2N,M100
对于 100 % 100\% 100% 的数据, 2 ≤ N , M ≤ 2000 2 \le N, M \le 2000 2N,M2000

数据保证起点 ( 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) xk<ik ak,j=.dpk,j(1x)
    即从 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 里面。
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)

  1. 向右转移: ∑ 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) xk<jk ai,k=.dpi,k(1x)
    即从 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 里面。
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)

  1. 向右下转移: ∑ 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) xk<min(i,j) aik,jk=.(1x)
    即从 i , j i, j i,j 开始向前,一直到 a i − k , j − k a_{i - k, j - k} aik,jk. 为止,并把 d p i − k , j − k dp_{i - k, j - k} dpik,jk 加在 d p i , j dp_{i, j} dpi,j 里面。
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,j0)。
如果 ( i , j ) (i, j) (i,j).,则加上 d p 3 , i − 1 , j dp_{3, i - 1, j} dp3,i1,j。(它既可以从前面转移,也可以从 ( i − 1 , j ) (i - 1, j) (i1,j) 转移)。

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

输入
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]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值