leetcode_935. Knight Dialer_动态规划_矩阵快速幂
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_动态规划_矩阵快速幂的更多相关文章
- 【CF1151F】Sonya and Informatics(动态规划,矩阵快速幂)
[CF1151F]Sonya and Informatics(动态规划,矩阵快速幂) 题面 CF 题解 考虑一个暴力\(dp\).假设有\(m\)个\(0\),\(n-m\)个\(1\).设\(f[i ...
- 【BZOJ5298】[CQOI2018]交错序列(动态规划,矩阵快速幂)
[BZOJ5298][CQOI2018]交错序列(动态规划,矩阵快速幂) 题面 BZOJ 洛谷 题解 考虑由\(x\)个\(1\)和\(y\)个\(0\)组成的合法串的个数. 显然就是把\(1\)当做 ...
- 【BZOJ4870】组合数问题(动态规划,矩阵快速幂)
[BZOJ4870]组合数问题(动态规划,矩阵快速幂) 题面 BZOJ 洛谷 题解 显然直接算是没法做的.但是要求的东西的和就是从\(nk\)个物品中选出模\(k\)意义下恰好\(r\)个物品的方案数 ...
- 【BZOJ1494】【NOI2007】生成树计数(动态规划,矩阵快速幂)
[BZOJ1494][NOI2007]生成树计数(动态规划,矩阵快速幂) 题面 Description 最近,小栋在无向连通图的生成树个数计算方面有了惊人的进展,他发现: ·n个结点的环的生成树个数为 ...
- CF954F Runner's Problem(动态规划,矩阵快速幂)
CF954F Runner's Problem(动态规划,矩阵快速幂) 题面 CodeForces 翻译: 有一个\(3\times M\)的田野 一开始你在\((1,2)\)位置 如果你在\((i, ...
- nyoj_148_fibonacci数列(二)_矩阵快速幂
fibonacci数列(二) 时间限制:1000 ms | 内存限制:65535 KB 难度:3 描述 In the Fibonacci integer sequence, F0 = 0, F ...
- fibonacci数列(二)_矩阵快速幂
描述 In the Fibonacci integer sequence, F0 = 0, F1 = 1, and Fn = Fn − 1 + Fn − 2 for n ≥ 2. For exampl ...
- 【BZOJ2004】公交线路(动态规划,状态压缩,矩阵快速幂)
[BZOJ2004]公交线路(动态规划,状态压缩,矩阵快速幂) 题面 BZOJ 题解 看到\(k,p\)这么小 不难想到状态压缩 看到\(n\)这么大,不难想到矩阵快速幂 那么,我们来考虑朴素的\(d ...
- 【BZOJ1009】GT考试(KMP算法,矩阵快速幂,动态规划)
[BZOJ1009]GT考试(KMP算法,矩阵快速幂,动态规划) 题面 BZOJ 题解 看到这个题目 化简一下题意 长度为\(n\)的,由\(0-9\)组成的字符串中 不含串\(s\)的串的数量有几个 ...
随机推荐
- 理解Objective-C Runtime (六)super
super 在Objective-C中,如果我们需要在类的方法中调用父类的方法时,通常都会用到super,如下所示: @interface MyViewController: UIViewContro ...
- 使用masonry手写约束
在iOS开发过程中,手写contraints是非常痛苦的一件事情,往往那么一丢丢功能要写大量的代码,非常容易发生错误,并且非常不方便调试.所以只有在不得以的情况下才采用手工方式写contraints, ...
- win7Setx修改环境变量
SETX.exe (Resource Kit, Windows 7) Set environment variables permanently, SETX can be used to set En ...
- 详述IntelliJ IDEA插件的安装及使用方法(图解)
intellij idea是一款非常优秀的软件开发工具,它拥有这强大的插件体系,可以帮助开发者完成很多重量级的功能.今天,我们来学习一下如何安装和卸载intellij idea的插件. Intelli ...
- 如何用JavaScript实现获取验证码的效果
转自:http://www.php.cn/js-tutorial-411734.html HTML部分: 1 2 3 4 5 6 7 <body onload='createCode()'> ...
- FTP相关内容
FTP相关介绍 FTP 1)File Transfer Protocol ( FTP ) 是相当古老的网络协议之一,他最主要的功能就是进行 Server端与 Client 端之间的档案传送的功能.这个 ...
- Objective-C中的字符串格式化输出(转载)
转自:http://www.cnblogs.com/jackbutler/archive/2012/04/05/2432828.html %@ 对象 %d, %i 整数 %u 无符整形 %f 浮点/双 ...
- angular源码剖析之Provider系列--QProvider
QProvider 简介 源码里是这么描述的: A service that helps you run functions asynchronously, and use their return ...
- Codeforces 1108F(克鲁斯卡尔的理解)
最小生成树会多样的情况是:两个或多个边等长且连通同样的两个并查集块. 所以可以跑一遍克鲁斯卡尔,每次把当前等长的边数出来,注意不要边找边并查,因为有一部分边是正常跑生成树我们也不会要他的,这种直接跳了 ...
- bryce1010专题训练——划分树
1.求区间第K大 HDU2665 Kth number /*划分树 查询区间第K大 */ #include<iostream> #include<stdio.h> #inclu ...
