https://leetcode.com/problems/knight-dialer/

在如下图的拨号键盘上,初始在键盘中任意位置,按照国际象棋中骑士(中国象棋中马)的走法走N-1步,能拨出多少种不同的号码。

解法一:动态规划,逆向搜索

class Solution
{
public:
vector<vector<int> > gra{{,},{,},{,},{,},{,,},
{},{,,},{,},{,},{,}};
const int mod=1e9+;
int knightDialer(int N)
{
int res=;
for(int i=; i<=; i++)
{
vector<vector<int>> dp(N+,vector<int>(,-));
dp[][i]=;
for(int j=;j<=;j++)
res = (res+dfs(N-,j,dp))%mod;
}
return res;
}
int dfs(int step,int num,vector<vector<int>>& dp)
{
if(dp[step][num]>=)
return dp[step][num];
if(step==)
return dp[step][num]=;
int ret=;
for(int i=;i<gra[num].size();i++)
ret = (ret + dfs(step-, gra[num][i], dp))%mod;
return dp[step][num]=ret;
}
};

解法二:动态规划,正向递推

class Solution
{
public:
vector<vector<int> > gra{{,},{,},{,},{,},{,,},
{},{,,},{,},{,},{,}};
const int mod=1e9+;
int knightDialer(int N)
{
int res=;
for(int i=; i<=; i++)
{
vector<vector<int>> dp(N+,vector<int>(,));
dp[][i]=;
for(int j=; j<=N-; j++)
for(int k=; k<=; k++)
for(int l=; l<gra[k].size(); l++)
dp[j][k] = (dp[j][k]+dp[j-][gra[k][l]])%mod;
for(int j=; j<=; j++)
res = (res+dp[N-][j])%mod;
}
return res;
}
};

问题一:要构造10次二维的vector,很耗时,dp[N][10]空间也有很大浪费。

改进:

将dp[j][k] = (dp[j][k]+dp[j-1][gra[k][l]])%mod;(当前状态由前一时刻状态推得)
改为dp[j+1][gra[k][l]] = (dp[j+1][gra[k][l]]+dp[j][k])%mod;(由当前时刻状态推下一时刻状态)
改进过后可以省去9次构造二维vector的开销,除此之外,递推更加高效(相比之下少了一层for)。
class Solution
{
public:
vector<vector<int> > gra{{,},{,},{,},{,},{,,},
{},{,,},{,},{,},{,}};
const int mod=1e9+;
int knightDialer(int N)
{
int res=;
int dp[][];
//vector<vector<int>> dp(N,vector<int>(10,0));
memset(dp,,sizeof(dp));
for(int i=; i<=; i++)
dp[][i]=;
for(int j=; j<=N-; j++)
for(int k=; k<=; k++)
for(int l=; l<gra[k].size(); l++)
dp[j+][gra[k][l]] = (dp[j+][gra[k][l]]+dp[j][k])%mod;
for(int j=; j<=; j++)
res = (res+dp[N-][j])%mod;
return res;
}
};

空间复杂度还没有还没优化,但是可以发现,递推关系只需要两个状态(当前状态和下一步状态),而不需要N个状态。

解法三:动态规划,矩阵快速幂

进一步使用矩阵运算来优化状态的递推关系,同时还可以使用快速幂,使最终时间复杂度优化到O(logN),空间复杂度优化到常数量级。但是C++自己实现矩阵稍微有点麻烦。使用python的numpy非常方便。

class Matrix
{
public:
Matrix(int row, int col);
Matrix(vector<vector<int>>& v);
Matrix operator * (const Matrix& rh)const;
Matrix& operator = (const Matrix& rh);
int GetRow(){return row_;}
int GetCol(){return col_;}int SumOfAllElements();
~Matrix();
private:
int row_,col_;
long long **matrix_;
};
Matrix::Matrix(int row, int col)
{
row_ = row;
col_ = col;
matrix_ = new long long* [row_];
for(int i=; i<row_; i++)
matrix_[i] = new long long[col_];
for(int i=; i<row_; i++)
for(int j=; j<col_; j++)
matrix_[i][j] = (i==j?:);
} Matrix::Matrix(vector<vector<int>>& v)
{
row_ = v.size();
col_ = v[].size();
matrix_ = new long long* [row_];
for(int i=; i<row_; i++)
matrix_[i] = new long long[col_];
for(int i=; i<row_; i++)
for(int j=; j<col_; j++)
matrix_[i][j] = v[i][j];
} Matrix Matrix::operator * (const Matrix& rh)const
{
Matrix result(row_,col_);
for(int i=; i<row_; i++)
for(int j=; j<col_; j++)
{
long long temp=;
for(int k=; k<col_; k++)
{
temp += matrix_[i][k]*rh.matrix_[k][j];
temp %= (int)1e9+;
}
result.matrix_[i][j] = temp;
}
return result;
} Matrix& Matrix::operator = (const Matrix& rh)
{
if(this==&rh)
return (*this);
for(int i=; i<col_; i++)
delete [] matrix_[i];
delete [] matrix_;
row_ = rh.row_;
col_ = rh.col_;
matrix_ = new long long* [row_];
for(int i=; i<row_; i++)
matrix_[i] = new long long[col_];
for(int i=; i<row_; i++)
for(int j=; j<col_; j++)
matrix_[i][j] = rh.matrix_[i][j];
return (*this);
} int Matrix::SumOfAllElements()
{
long long result=;
for(int i=; i<row_; i++)
for(int j=; j<col_; j++)
{
result += matrix_[i][j];
result %= (int)1e9+;
}
return result;
}
Matrix::~Matrix()
{
for(int i=; i<col_; i++)
delete [] matrix_[i];
delete [] matrix_;
}
//以上为矩阵类的实现,仅能满足此题方阵乘法,其他的功能性质没有考虑 class Solution
{
public: const int mod=1e9+;
int knightDialer(int N)
{
vector<vector<int> > matrix
{
{,,,,,,,,,},
{,,,,,,,,,},
{,,,,,,,,,},
{,,,,,,,,,},
{,,,,,,,,,},
{,,,,,,,,,},
{,,,,,,,,,},
{,,,,,,,,,},
{,,,,,,,,,},
{,,,,,,,,,},
};
Matrix matrix1(matrix);
Matrix result(matrix1.GetRow(), matrix1.GetCol());
int step = N-;
while(step>)
{
if(step&)
result = result * matrix1;
step >>= ;
matrix1 = matrix1 * matrix1;
}
return result.SumOfAllElements();
}
};

leetcode_935. Knight Dialer_动态规划_矩阵快速幂的更多相关文章

  1. 【CF1151F】Sonya and Informatics(动态规划,矩阵快速幂)

    [CF1151F]Sonya and Informatics(动态规划,矩阵快速幂) 题面 CF 题解 考虑一个暴力\(dp\).假设有\(m\)个\(0\),\(n-m\)个\(1\).设\(f[i ...

  2. 【BZOJ5298】[CQOI2018]交错序列(动态规划,矩阵快速幂)

    [BZOJ5298][CQOI2018]交错序列(动态规划,矩阵快速幂) 题面 BZOJ 洛谷 题解 考虑由\(x\)个\(1\)和\(y\)个\(0\)组成的合法串的个数. 显然就是把\(1\)当做 ...

  3. 【BZOJ4870】组合数问题(动态规划,矩阵快速幂)

    [BZOJ4870]组合数问题(动态规划,矩阵快速幂) 题面 BZOJ 洛谷 题解 显然直接算是没法做的.但是要求的东西的和就是从\(nk\)个物品中选出模\(k\)意义下恰好\(r\)个物品的方案数 ...

  4. 【BZOJ1494】【NOI2007】生成树计数(动态规划,矩阵快速幂)

    [BZOJ1494][NOI2007]生成树计数(动态规划,矩阵快速幂) 题面 Description 最近,小栋在无向连通图的生成树个数计算方面有了惊人的进展,他发现: ·n个结点的环的生成树个数为 ...

  5. CF954F Runner's Problem(动态规划,矩阵快速幂)

    CF954F Runner's Problem(动态规划,矩阵快速幂) 题面 CodeForces 翻译: 有一个\(3\times M\)的田野 一开始你在\((1,2)\)位置 如果你在\((i, ...

  6. nyoj_148_fibonacci数列(二)_矩阵快速幂

    fibonacci数列(二) 时间限制:1000 ms  |  内存限制:65535 KB 难度:3   描述 In the Fibonacci integer sequence, F0 = 0, F ...

  7. fibonacci数列(二)_矩阵快速幂

    描述 In the Fibonacci integer sequence, F0 = 0, F1 = 1, and Fn = Fn − 1 + Fn − 2 for n ≥ 2. For exampl ...

  8. 【BZOJ2004】公交线路(动态规划,状态压缩,矩阵快速幂)

    [BZOJ2004]公交线路(动态规划,状态压缩,矩阵快速幂) 题面 BZOJ 题解 看到\(k,p\)这么小 不难想到状态压缩 看到\(n\)这么大,不难想到矩阵快速幂 那么,我们来考虑朴素的\(d ...

  9. 【BZOJ1009】GT考试(KMP算法,矩阵快速幂,动态规划)

    [BZOJ1009]GT考试(KMP算法,矩阵快速幂,动态规划) 题面 BZOJ 题解 看到这个题目 化简一下题意 长度为\(n\)的,由\(0-9\)组成的字符串中 不含串\(s\)的串的数量有几个 ...

随机推荐

  1. 识别String类型变量的问题

    碰到了android无法识别string的问题 Cursor cursor = db.query(true, "user", new String[]{"id" ...

  2. 【CQ18阶梯赛第8场】题解

    [A:HDU2032 杨辉三角]: 简单的递推,或者是基础的DP: 但是只有杨润东一个人1A,整体准确率只有8/37,具体原因不详. 经验:提交前一定要试一下比较特殊的数据或者最大的数据.其次,为了保 ...

  3. 「LuoguP2170」 选学霸(01背包

    Description 老师想从N名学生中选M人当学霸,但有K对人实力相当,如果实力相当的人中,一部分被选上,另一部分没有,同学们就会抗议.所以老师想请你帮他求出他该选多少学霸,才能既不让同学们抗议, ...

  4. Code-NFine:下来框和复选框

    ylbtech-Code-NFine:下来框和复选框 1.返回顶部 1. 1.1 html $("#F_OrganizeId").bindSelect({ url: "/ ...

  5. bzoj4773

    矩阵乘法 ...爆零了... 想到Floyd,却不知道怎么限制点数... 其实我们只要给Floyd加一维,dp[i][j][k]表示当前走过了i个点,从j到k的最短距离,然后这样可以倍增,最后看是否有 ...

  6. JS获取子节点、父节点和兄弟节点的方法实例总结

    转自:https://www.jb51.net/article/143286.htm 本文实例讲述了JS获取子节点.父节点和兄弟节点的方法.分享给大家供大家参考,具体如下: 一.js获取子节点的方式 ...

  7. 斯坦福CS231n—深度学习与计算机视觉----学习笔记 课时24&&25

    课时24 深度学习开源库使用介绍(上) Caffe 被用于重新实现AlexNet,然后用AlexNet的特征来解决其他事情 用C++书写的,可以去GitHub上面读取源代码 主要四个类: Blob可以 ...

  8. E20180410-sl

    category n. 类型,部门,种类,类别,类目; [逻,哲] 范畴; 体重等级;

  9. 20170412-sl

    force n实力,武力 v强迫 ---------------20170413-sl----------------------- discard   n/v 放弃 fetch n/v 拿,取 pu ...

  10. bzoj 5498: [2019省队联测]皮配【dp】

    是个神仙dp-- 参考:https://www.luogu.org/blog/xzz-233/solution-p5289 设f[i][j][k]是前i个有限制的城市,所有学校中选蓝色阵营有j人,有限 ...