关于数位DP的个人总结

1.数位dp,可以利用dfs来暴力搜索,dp来继续记忆化的减枝,适合用于解决高的数量级的,跟数的位数有关系的问题

2.dp[pos][sta],pos表示的是遍历的数的层数(例如十位百位千位),层数是从大到小的,遍历到-1层则表示当前的数已经形成,则可以返回当前的数的在问题中所计算出的值temp,sta表示的是对于题目,有些不同的数据可以有的相同的状态,例如:hdu中的不要62(统计一个区间中没有4和62出现的数的数目为多少),显然不同的位数相同的状态就是是否含有6,dp[pos][sta]//sta表示是否含有6,有为1无为0,当百位为0,十位为6时,要调用的是dp[0][1](dp[0][1]={0,1,3,4,5,6,7,8,9}=9),而不是dp[0][0]={0,1,2,3,4,5,6,7,8,9}=10

模板:

int a[pos]//用来储存实际参数的各个数位的值
int dp[pos][sta] //pos用来表示当前的层数,sta用来表示可以公用的状态
int dfs(int pos,int sta,bool limit)//pos表示下一层是哪一层,sta下一个层数遍历的位置可一公用的状态,limit用来限制当前的层数是否需要限制最高的遍历的数 
{
	int i,j;
	if(pos==-1)
	{
		return  dp[pos][sta];//当前的数成型返回结果 
	}	
	
	if(!limt&&dp[pos][sta]!=0)
	{
		return dp[pos][sta];//记忆化的好处体现在这里,如果遇到可以公用的状态则可以直接的调用,需要没有限制才可以调用,因为调用的dp[pos][sta]表示的是前一层数的结果例如(214),百位为2时,十位只能是0,1如果遍历dp[1][sta]则十位为0-9超出了范围 
	}
	
	int up=limit?a[pos]:9;//确定范围 
	int temp=0;
 	for(i=0;i<=up;i++)
 	{
	 	if().....//根据题意跳过不符合题意的结果
		 temp+=dfs(pos-1,sta...,limit&&i==up); 
 	}
 	
 	if(!limit)
 	dp[pos][sta]=temp;//记忆化 
 
 
 	return temp;
	
}
int solve(int x)
{
	int cnt=0;
	while(x)
	{
		a[cnt++]=x%10;
		x/=10;	
	}	
	return  dfs(cnt,sta,1);
} 	

猜你喜欢

转载自blog.csdn.net/com_ice/article/details/79298295
今日推荐