范围内有多少个数字满足条件

时间:2018-11-09 16:55:32

标签: algorithm dynamic-programming

我遇到了一个数字动态编程问题。

让x是一个没有相邻数字的数字,使得abs(x[i] - x[i+1]) <= 1,即,如果获取x任意两个相邻数字之差的绝对值,则得到的数字将大于1。例如,数字1和2不能相邻,数字5和5不能相邻。

目标是计算x在[A,B]范围内的数量。我知道这是一个digit dynamic programming问题,但我不知道我的尝试出了什么问题。

示例: 对于输入:110 130,输出应为1(因为只有130满足该条件)。我的代码正确输出1,但在其他输入上失败。

这是我的尝试。我知道我需要添加备忘录,但是我想在之前就得到算法。

#include <vector>
#include <iostream>
#include <algorithm>
#include <string>
#include <cstring>

using namespace std;

int dp[5001][10][2];
const int MOD = 10000;

int count(vector<int> &digits, int idx, int digit_before, int less, int leading_zero) {
    if (idx == digits.size()) return 1;

    if (dp[idx][digit_before][leading_zero] != -1 && less)
        return dp[idx][digit_before][leading_zero];

    int cnt = 0;
    int k = less ? 9 : digits[idx];

    for (int i = 0; i <= k; i++) {
        int zero = (i == 0) ? leading_zero : 0;
        int new_less = (i == k) ? less : 1;
        if (!leading_zero && abs(digit_before - i) <= 1) continue;
        cnt += count(digits, idx + 1, i, new_less, zero);
        cnt %= MOD;
    }

    if (less) {
        dp[idx][digit_before][leading_zero] = cnt;
    }

    return cnt;
}

int main() {
    memset(dp, -1, sizeof(dp));

    string a, b;
    cin >> a >> b;

    vector<int> a_digits{};
    for (auto i = 0; i < a.size(); i++) {
        a_digits.push_back(a[i] - '0');
    }

    vector<int> b_digits{};
    for (auto i = 0; i < b.size(); i++) {
        b_digits.push_back(b[i] - '0');
    }

    auto i = a_digits.size() - 1;
    for (; a_digits[i] == 0; i--);
    a_digits[i]--;

    cout << (count(b_digits, 0, 0, 0, 1) - count(a_digits, 0, 0, 0, 1)) % MOD;

    return 0;
}

1 个答案:

答案 0 :(得分:0)

您的代码中有几个错误。例如:

// try for a_digits = {1,0,0,0};
auto i = a_digits.size() - 1;
for (; a_digits[i] == 0; i--);
a_digits[i]--;

您的dp[idx][digit_before][leading_zero]状态不正确。应该是dp[idx][digit_before][leading_zero][less],因为int k = less ? 9 : digits[idx];取决于less

另外,由于memset(dp, -1, sizeof(dp));可能会有所不同,因此每次调用count(vector<int> &digits, int idx, int digit_before, int less, int leading_zero)之前都必须设置vector<int> &digits

固定代码如下:

#include <vector>
#include <iostream>
#include <algorithm>
#include <string>
#include <string.h>

using namespace std;

int dp[5001][10][2][2];
const int MOD = 10000;

int count(vector<int> &digits, int idx, int digit_before, int less, int leading_zero) {
    if (idx == digits.size()) return 1;

    if (dp[idx][digit_before][leading_zero][less] != -1)
        return dp[idx][digit_before][leading_zero][less];

    int cnt = 0;
    int k = less ? 9 : digits[idx];

    for (int i = 0; i <= k; i++) {
        int zero = (i == 0) ? leading_zero : 0;
        int new_less = (i == k) ? less : 1;
        if (!leading_zero && abs(digit_before - i) <= 1) continue;
        cnt += count(digits, idx + 1, i, new_less, zero);
        cnt %= MOD;
    }

    dp[idx][digit_before][leading_zero][less] = cnt;

    return cnt;
}

int main() {
    string a, b;
    cin >> a >> b;

    vector<int> a_digits{};
    for (auto i = 0; i < a.size(); i++) {
        a_digits.push_back(a[i] - '0');
    }

    vector<int> b_digits{};
    for (auto i = 0; i < b.size(); i++) {
        b_digits.push_back(b[i] - '0');
    }

    auto i = a_digits.size() - 1;
    for (; a_digits[i] == 0; i--);
    a_digits[i]--;
    if(a_digits[i] == 0) {
        i++;
        for(; i <= a_digits.size(); i++) {
            a_digits[i] = 9;
        }
    }

    memset(dp, -1, sizeof(dp));
    int cnt1 = count(b_digits, 0, 0, 0, 1);
    memset(dp, -1, sizeof(dp));
    int cnt2 = count(a_digits, 0, 0, 0, 1);
    cout << ( cnt1 - cnt2 + MOD ) % MOD;

    return 0;
}