1. 程式人生 > >動態規劃專題(三)——數位DP

動態規劃專題(三)——數位DP

前言

數位DPDP 真的是最噁心DPDP

簡介

看到那種給你兩個數,讓你求這兩個數之間符合條件的數的個數,且這兩個數非常大,這樣的題目一般就是 數位DPDP 題。

數位DPDP一般都用於計數

具體實現

數位DPDP有兩種實現方法:DPDP預處理+亂搞求答案以及記憶化搜尋

個人感覺用記憶化搜尋來實現要比較容易一些(第一種做法我是真的不會)。

數位DPDP在求解的過程中運用了字首和的思想,即要求lrl\sim r範圍內的解的個數,就相當於0r0\sim r範圍內的解的個數減去0l10\sim l-1範圍內解的個數即可。

模板

貼一波記憶化搜尋

的模板:

class Class_DigitalDP//數位DP(記憶化搜尋實現)
{
	private:
		#define Size 15//如果是int範圍內,數字長度不會超過15,這個Size要視題目而定
		int len,num[Size],f[Size][10];//len儲存數字長度,num記錄數字的每一位,f則用於記憶化
		inline void Init(LL x) {len=0;while(x) num[++len]=x%10,x/=10;num[len+1]=0;}//初始化,將x這個數字按位儲存下來
		inline int dfs(int x,int s,int flag)//x記錄剩餘的位數,s記錄當前的狀態,flag記錄當前是否肯定在求解的範圍內(0表示不一定,1表示一定)
{ register int i,lim=9,w=0;//w用於統計答案 if(!x) return OK(s);//如果剩餘位數為0,就判斷當前狀態是否滿足條件,並退出函式 if(flag&&~f[x][s]) return f[x][s];//如果當前狀態肯定在求解範圍內,且已訪問並求解過當前狀態,就返回曾經求解出的答案 if(!flag) (Right(num[x])&&(w+=dfs(x-1,GetStatus(s,num[x]),0),0),lim=num[x]-1;//如果不保證在求解範圍內,則對這一位上的最大值單獨處理,並仍不能保證在求解範圍內
for(i=0;i<=lim;++i) if(Right(i)) w+=dfs(x-1,GetStatus(s,i),1);//列舉每一個數字,如果這個數字符合條件,就繼續搜尋 if(flag) f[x][s]=w;//如果當前狀態肯定在求解的範圍內,就將求解出的答案記錄下來,實現記憶化 return w;//返回答案 } public: Class_DigitalDP() {for(register int i=0,j;i<Size;++i) for(j=0;j<9;++j) f[i][j]=-1;}//初始化f陣列為-1 inline int GetAns(int x) {return (void)(Init(x)),dfs(len,0,0);}//將這個數按位儲存下來,然後記憶化搜尋求解 }DigitalDP;

幾道例題

照常貼幾道例題:

一道二進位制的數位DPDP,可以發現用DPDP預處理得到的是一個楊輝三角形… …

比較經典的數位DPDP題,關鍵在於要判前導00

應該是這幾道題裡我唯一一道寫記憶化搜尋的,需要加上一點噁心的數學轉化。