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. 90年代经典“手游”—拼图板小游戏Opencv实现

    80后可能还对儿时玩过的一种经典木质的拼图板游戏记忆犹新,一般是一种4*4或5*5规格的手持活动板,通过挪动每个小板子的位置,拼出来板子上完整的图像,那时候还没有网吧,手机也还是大哥大的天下,所以这也 ...

  2. 「 LuoguT37042」 求子序列个数

    Description 给定序列 A, 求出 A 中本质不同的子序列 (包含空的子序列) 个数模 10^9+ 7 的结果. 一个序列 B 是 A 的子序列需要满足 A 删掉某些元素后能够得到 B. 两 ...

  3. Ski Course Design

    链接 分析:读题!读题!读题!重要的事说三遍,中文翻译漏掉了一个重要的地方,每个只能用一次,调了一下午还以为标程错了,其实就是找一段长为17的区间,然后使所有都处于这个区间中代价最小,暴力枚举即可. ...

  4. 怎么解决Failed to load the JNI shared library

    怎么解决Failed to load the JNIshared library   解决Failed to load the JNIshared library唯一的方法就是重新安装eclipse, ...

  5. Video.js事件

    Home 膘叔 » Archives 文章: 备份一个video的JS [打印] 分类: Javascript 作者: gouki 2012-02-16 17:58 备份一个JS,不是为了代码很优秀, ...

  6. 6-5 Haar特征2

    在遍历的过程中还需要考虑到一个步长的问题.这个模板一次滑动10个像素,那么总共就需要滑动9次.再加上最开始的第0次,合计在水平方向上和竖直方向上分别都有10个这样的模板,总共也就是100个模板.要计算 ...

  7. HDU 1995 汉诺塔V (水题)

    题意:.. 析:2^n-i 代码如下: #pragma comment(linker, "/STACK:1024000000,1024000000") #include <c ...

  8. gdb调试带参数的程序 (转载)

    转自:http://www.cnblogs.com/rosesmall/archive/2012/04/10/2440514.html 一般来说GDB主要调试的是C/C++的程序.要调试C/C++的程 ...

  9. Servlet3.0-使用注解定义过滤器(Filter)

    本人正在学javaweb,遇到了在eclipse中,servlet3.0过滤器需不需要配置web.xml文件?通过实践得出结论,不用配置,只需要@WebFilter(filterName=" ...

  10. bzoj 1003: [ZJOI2006]物流运输【spfa+dp】

    预处理出ans[i][j]为i到j时间的最短路,设f[i]为到i时间的最小代价,转移显然就是 f[i]=min(f[j-1]+ans[j][i]*(i-j+1)+k); #include<ios ...