[动态规划]:426.拨号器

111 阅读2分钟

问题描述

小F正在使用一个骑士跳跃方式的拨号器。这个拨号器是一个类似电话键盘的 3x4 矩阵,每个数字对应一个单元格,骑士只能站在蓝色数字单元格上进行跳跃(数字 190)。骑士的移动方式和国际象棋中的马相同:它可以垂直移动两个单元格并水平移动一个单元格,或水平移动两个单元格并垂直移动一个单元格,形成 "L" 形。

123
456
789
*0#

给定一个整数 n,你需要帮助小F计算骑士可以拨出的所有长度为 n 的不同电话号码的数量。骑士可以从任何数字开始,并在 n-1 次有效跳跃后得到一个有效号码。答案可能非常大,因此你需要返回对 10^9 + 7 取模的结果。


测试样例

样例1:

输入:n = 1 输出:10

样例2:

输入:n = 2 输出:20

样例3:

输入:n = 3 输出:46

样例4:

输入:n = 4 输出:104

解题思路

  • 考虑0-9每个数字可以由哪些数字跳L型过来

    • 0: 4, 6
    • 1: 6, 8
    • 2: 7, 9
    • 3: 4, 8
    • 4: 0, 3, 9
    • 5: 没有
    • 6: 0, 1, 7
    • 7: 2, 6
    • 8: 1, 3
    • 9: 2, 4
  • n=1n = 1时,每个数字都是单独的,即 f[09]=1f[0-9] = 1

  • n=2n = 2时,f[i]f[i]表示数字ii的组合数量,那么f[i]=f[a]+f[b]...f[i] = f[a] + f[b]...(根据上面来)

  • 由于更新f[i]f[i]会导致后面使用f[i]f[i]产生变化,我们利用tt数组暂存,遍历完后更新ff

核心代码

int solution(int n) {
    long long mod = 1e9+7;
    vector<int>f(10,1);
    for(int i = 1; i < n; i++) {
        vector<int>t(10);
        t[0] = (f[4] + f[6])%mod;
        t[1] = (f[6] + f[8])%mod;
        t[2] = (f[7] + f[9])%mod;
        t[3] = (f[4] + f[8])%mod;
        t[4] = (f[0] + f[3] + f[9])%mod;
        t[6] = (f[0] + f[1] + f[7])%mod;
        t[7] = (f[2] + f[6])%mod;
        t[8] = (f[1] + f[3])%mod;
        t[9] = (f[2] + f[4])%mod;
        f = t;
    }
    int ans = 0;
    for(int i = 0; i < f.size(); i++) ans = (ans + f[i]) % mod;
    return ans;
}