數位DP——2018數,吉比特筆試題

題目:給定一個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爲當前是否有限制。
	}
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章