題目:給定一個n求1到n之間的2018數,2018數數字中含有 2018即爲2018數例如,210198,32108;10218不是2018數,
數據範圍1e9;
解法:數位dp,數位dp理解,記憶話加遞歸,將每一位的數字狀態保存下來,以後用到時直接調用結果
代碼中寫了我對此題的理解 ,可能對大家有點幫助,數位dp入門參看:https://blog.csdn.net/qq_37632935/article/details/81315404#commentBox
#include<iostream>
#include<algorithm>
#include<string>
#include<set>
#include<map>
#include<stdio.h>
#include<string.h>
using namespace std;
const int n = 11;
int dp[n][5][2];
int dat[5] = { 0,2,0,1,8 };
int num[n+1];
int dfs(int pos, int pn, int lim){
if (pos == 0)return pn == 5 ? 1 : 0;//從高位向低位走到最後,5代表2018走完即前面出現了2018
if (dp[pos][pn][lim]!=-1 && !lim)return dp[pos][pn][lim];//dp[pos][pn][lim]走過,並且當前是沒有被限制,即可以隨便取.記憶話
int top = lim ? num[pos] : 9;//當前是被限制的則取當前位的值,否則去9,例子3567,當第一位去2時,第二位可以隨便取,因爲最大
//爲2999<3567
int tn = 5;
int ans = 0;
for (int i = 0; i <= top; i++) {
tn = 5;
if(pn<5){//大於等於5即前面的位數已經出現2018的組合,後面的可以全部加起來了
if (dat[pn] == i)tn = pn + 1;//當前位是預期結果,預期結果爲向後移一位如,2018當前是2,那麼,下次判斷就應該判1了
else tn = pn;
}
ans += dfs(pos - 1, tn, lim && (i == top));//當前位只有在前一位也受限制時才受限制。
}
if (!lim)dp[pos][pn][lim] = ans;
return ans;
}
int main() {
memset(dp, -1, sizeof(dp));
int m;
while (cin >> m) {
int k = 0;
while (m) {
num[++k] = m % 10;
m = m / 10;
}
cout << dfs(k, 1, 1);//k位數,從第k位(最高位)開始,第一個1代表dat的2,去判斷是否是2,第二個1爲當前是否有限制。
}
}