leetcode 935 骑士拨号器 动态规划法

国际象棋中的骑士可以按下图所示进行移动:

《leetcode 935 骑士拨号器 动态规划法》 .           《leetcode 935 骑士拨号器 动态规划法》

这一次,我们将 “骑士” 放在电话拨号盘的任意数字键(如上图所示)上,接下来,骑士将会跳 N-1 步。每一步必须是从一个数字键跳到另一个数字键。

每当它落在一个键上(包括骑士的初始位置),都会拨出键所对应的数字,总共按下 N 位数字。

你能用这种方式拨出多少个不同的号码?

因为答案可能很大,所以输出答案模 10^9 + 7

示例 1:

输入:1
输出:10

示例 2:

输入:2
输出:20

示例 3:

输入:3
输出:46

提示:

  • 1 <= N <= 5000

分析:能看到运行的轨迹,一个号码,则是0-9 10种情况,如果是2个及以上,5则不可能,因为在5无法移动到任何地方,对于这9个数字我们可以把情况都做出来。从一个数字到下一个位置有如下映射:

0 = > {4, 6};
1 =  > {8, 6};
2 = > {7, 9};
3=> {4, 8};
4=> {3, 9, 0};
5= > {};
6=> {1, 7, 0};
7= > {2, 6};
8= > {1, 3};
9=> {2, 4};

dp[n][10],储存拨号次数下,如果第n次拨号0-9数字时,一共会有多少次拨号方式,由dp[n-1–0][10]的结果来决定。

代码如下:

#define REP(i,s,t) for(int i=(s);i<(t);i++)
#define RESET(x,v) memset(x,v,sizeof(x))//
typedef vector<int>vec;
vec number[10];
const int mod = 1e9+7;//膜
int dp[5001][10];
class Solution {
public:
  int knightDialer(int N) {
    number[0] = vec({4,6});number[1] = vec({6,8});number[2] = vec({7,9});
    number[3] = vec({4,8});number[4] = vec({0,3,9});number[6] = vec({0,1,7});
    number[7] = vec({2,6});number[8] = vec({1,3});number[9] = vec({2,4});//每个键能取到的下一个键
    RESET(dp, 0);//初始化
    REP(d,0,10) dp[1][d] = 1;//只播一个键时每个号码都可以摁一次
    REP(i,2,N+1) {
      REP(d,0,10) {
        int pre = dp[i-1][d];//记录上一次结果数量
        if (pre == 0) continue;//如果上一次这个号码情况下已经行不通,则跳过
        REP(k,0,number[d].size()) {
          int d2 = number[d][k];
          dp[i][d2] = (dp[i][d2] + pre) % mod;//只要在第i次拨号,访问到当前的d2这个号码,就将 这个顺序之前的次数加进来更新
        }
      }
    }
    int ans = 0;
    REP(d,0,10) ans = (ans + dp[N][d]) % mod;//播N次时从0-9一共有多少次拨号方式
    return ans;
  }
};

《leetcode 935 骑士拨号器 动态规划法》

    原文作者:骑士周游问题
    原文地址: https://blog.csdn.net/sunnanhunan/article/details/83786380
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞