一、题目描述
国际象棋中的骑士可以按下图所示进行移动:
我们将 “骑士” 放在电话拨号盘的任意数字键(如上图所示)上,接下来,骑士将会跳 N-1 步。每一步必须是从一个数字键跳到另一个数字键。
每当它落在一个键上(包括骑士的初始位置),都会拨出键所对应的数字,总共按下 N
位数字。
你能用这种方式拨出多少个不同的号码?
因为答案可能很大,所以输出答案模 10^9 + 7
。
示例 1:
输入:1 输出:10
示例 2:
输入:2 输出:20
示例 3:
输入:3 输出:46
二、题目分析
1)动态规划。状态定义:dp[i][j]代表从j开始跳i步的可能性
2)辅助条件:建立一个map<int,vector<int>>,代表谁经过一步能跳到j位置
3)初始化dp[0][0-9]=1;
4)状态转移:dp[i][j]+=dp[i-1][mp[j][k]],0<=k<=mp[j].size()-1;
5)结果:sum(dp[n-1][0-9])
三、代码实现
class Solution { public: int knightDialer(int N) { if (!N)return 10; vector <vector<int>>dp(N, vector<int>(10)); int i, j, k; int Max = pow(10, 9) + 7; for (i = 0; i < 10; ++i) { dp[0][i] = 1; } map<int, vector<int>>mp; mp.insert({ 0,{ 4,6 } }), mp.insert({ 1,{ 6,8 } }), mp.insert({ 2,{ 7,9 } }), mp.insert({ 3,{ 4,8 } }), mp.insert({ 4,{ 0,3,9 } }); mp.insert({ 5,{} }), mp.insert({ 6,{ 0,1,7 } }), mp.insert({ 7,{ 2,6 } }), mp.insert({ 8,{ 1,3, } }), mp.insert({ 9,{ 2,4 } }); for (i = 1; i < N; ++i) { for (j = 0; j <= 9; ++j) { for (k = 0; k < mp[j].size(); ++k) { dp[i][j] += dp[i - 1][mp[j][k]]; if (dp[i][j] > Max) dp[i][j] = dp[i][j] % Max; } } } int sum = 0; for (int i = 0; i <=9; ++i) { sum += dp[N - 1][i]; if (sum > Max)sum %= Max; } return sum; } };