數位DP專題總結
阿新 • • 發佈:2019-02-05
簡介
數位DP是一類非常精巧的動態規劃,它解決的問題是
000 | 001 | 099 | |
---|---|---|---|
100 | 101 | 199 | |
200 | 201 | 299 | |
300 | 301 | 399 | |
400 | 401 | 469 |
顯然,如果我們能夠逐段求出答案就可以找到最終答案。如何巧妙地組織這個解空間,然後逐步求解呢?
可以按照下圖組織:
上圖中存在比較多的重疊子問題,可以使用動態規劃來解決;需要特別強調的是如果百位為4或者百位為4且十位為6的時候,其對應的子問題,不具有通用性,不應該備忘。上述條件被稱為limit條件。
引入
請計算
如何求解這個問題呢?
首先看百位上的情況,百位一定是受限制的,其數值只能取0到4,而不是0到9。我們來考慮百位為0、1的情況,只需計算000到099中不包行49的數的個數就好了;當考慮百位為2時,情況變得複雜起來,其十位只能考慮0、1、2、3,而非0到9。百位為0、1不滿足limit條件,其對應的子問題(00到99中不含49的數)有一定的通用性需要記錄,以便複用。
上程式碼
#include<map> #include<vector> #include<unordered_set> #include<unordered_map> #include<list> #include<queue> #include<deque> #include<stack> #include<iostream> #include<set> using namespace std; const int MAX_LEN = sizeof(int) / sizeof(char) * 8; class Solution { public: Solution(int x) { this->x = x; memset(dp, (char)(-1), sizeof(dp)); } int work() { string d = this->init(); return this->dfs((int)d.size() - 1, d, true, 0); } private: string init() { string d; int x = this->x; while (x) { int tmp = x % 10; x /= 10; d.push_back(tmp); } return d; } int dfs(int pos, string& d, bool limit, int state) { if (pos == -1) { if (state == 49) { return 1; } else { return 0; } } if (!limit && dp[pos][state] != -1) return dp[pos][state]; int maxNum = limit ? d[pos] : 9; int cnt = 0; for (int dNum = 0; dNum <= maxNum; ++dNum) { if (state == 4 && dNum == 9) { cnt += dfs(pos - 1, d, limit&&d[pos]==dNum, 49); } else if (state == 49) { cnt += dfs(pos - 1, d, limit&&d[pos]==dNum, 49); } else { cnt += dfs(pos - 1, d, limit&&d[pos]==dNum, dNum == 4 ? 4 : 0); } } if (!limit) { dp[pos][state] = cnt; } return cnt; } int x; int dp[MAX_LEN][2]; }; int main() { int x; cin>>x; Solution s(x); cout<<"result:\t"; cout<<s.work()<<endl; return 0; }