文章目录
写在前面
看题解看了半天都看不懂,看了视频也看了好久······,最后还是自己手动模拟才懂的,大佬们写的代码非常好,自己根本想不到该如何用代码实现出来,还是得多刷题,多见一些新题型
题目来源
思路
考点:DP+三维数组
这里用到三维是因为坐标需要二维来建立,另外每个坐标还需要存储路径的数量 ,因此必须多开一维
既然是整除的题目,那必然跟取模 有很大关系,例如 14 + 4 对 3 取模 14+4对3取模 14+4对3取模 我们可以看成 14 % 3 + 4 % 3 = ( 2 + 1 ) % 3 = 0 14\%3+4\%3=(2+1)\%3=0 14%3+4%3=(2+1)%3=0
首先定义 f i j v 表示从左上走到 ( i , j ) ,且路径和模 k 的结果为 v 时的路径数 fijv表示从左上走到 (i,j),且路径和模 k 的结果为 v 时的路径数 fijv表示从左上走到(i,j),且路径和模k的结果为v时的路径数
先看样例:(k=3)

那么路径和取模3为:
2 1 2
2 (2,1) (0,1,1)
2 (0,0,2) (0,0,1,2,2,2)
首先先定义边界, f 0 0 2 = 1 , 至于 f 0 0 0 和 f 0 0 1 肯定为 0 f002=1,至于f000和f001肯定为0 f002=1,至于f000和f001肯定为0
然后 f 0 1 1 = 1 ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ,先看 f 1 1 这个点,每个点只跟上边的点和左边的点有关,由于 g r i d i j = 0 , 那么加上左边和上边的路径和分别为 1 , 2 ,所以 f 1 1 1 = f 1 1 2 = 1 , 后面同理,最后算的是 f m − 1 n − 1 0 , 算出最后可以被 3 整除的路径数量 f011=1······,先看f11这个点,每个点只跟上边的点和左边的点有关,由于gridij=0,那么加上左边和上边的路径和分别为1,2,所以f111=f112=1,后面同理,最后算的是fm-1n-10,算出最后可以被3整除的路径数量 f011=1⋅⋅⋅⋅⋅⋅,先看f11这个点,每个点只跟上边的点和左边的点有关,由于gridij=0,那么加上左边和上边的路径和分别为1,2,所以f111=f112=1,后面同理,最后算的是fm−1n−10,算出最后可以被3整除的路径数量
模拟如此,代码如何实现呢?
参考模拟,状态转移方程就为:
f i + 1 j + 1 v = ( f i + 1 j ( v + k − g r i d \[ i j % k ) % k ] + f i j + 1 ( v + k − g r i d \[ i j % k ) % k ] ) ] % m o d fi+1j+1v=(fi+1j(v+k-grid\[ij\%k)\%k]+fij+1(v+k-grid\[ij\%k)\%k])]\%mod fi+1j+1v=(fi+1j(v+k−grid\[ij%k)%k]+fij+1(v+k−grid\[ij%k)%k])]%mod
首先,防止下标越界,让 i 和 j i和j i和j都+1
f i + 1 j + 1 v 为路径和模 k 的结果为 v 时的路径数 fi+1j+1v为路径和模 k 的结果为 v 时的路径数 fi+1j+1v为路径和模k的结果为v时的路径数
( v + k − g r i d i j % k ) % k 本质上是 v − g r i d i j ,即当前 v 的状态由上边以及左边 v − g r i d i j 状态而来 (v+k-gridij\%k)\%k本质上是v-gridij,即当前v的状态由上边以及左边v-gridij状态而来 (v+k−gridij%k)%k本质上是v−gridij,即当前v的状态由上边以及左边v−gridij状态而来
至于取模k的操作就是防止下标越界
接下来看代码
code
cpp
class Solution {
public:
int numberOfPaths(vector<vector<int>>& grid, int k) {
int m=grid.size(),n=grid[0].size();
int mod=1e9+7;
int f[m+1][n+1][k];
memset(f,0,sizeof f);
f[1][0][0]=1;//初始化
for(int i=0;i<m;++i)
for(int j=0;j<n;++j)
for(int v=0;v<k;++v){
f[i+1][j+1][v]=(f[i+1][j][(v+k-grid[i][j]%k)%k]+f[i][j+1][(v+k-grid[i][j]%k)%k])%mod;
}
return f[m][n][0];
}
};
制作不易,点个赞吧QVQ