windy数

题目

数位DP

记忆化搜索来实现

dfs设五个参数 pos,len,pre,sta,limit;

pos为当前枚举到第几位,从高往低枚举。

pos 为当前枚举到第几位,从高往低枚举。
len 有没有前导零,0代表有,1代表没有
pre 当前位的上一位
sta 设的状态,这题有10个,为0~9分别代表当前位上是几
limit 高位标记

设一个 f 数组

f[pos][pre][sta]为位数为pos,上一位为pre,当前状态为sta时的答案

枚举每一位上的数字(0~9)

如果有高位标记,那么最多枚举到a[pos];

a[i]表示这个数的第i位是多少

那么很显然当abs(pre-i)<2就得跳过这个数

上代码

#include<cstdio>
#include<cstring>
#include<cmath>
using namespace std;
int f[100][10][100],a[100];
int dfs(int pos,int len,int sta,int pre,bool limit)
{
	if (pos==0) return 1;
	if (!limit&&f[pos][sta][pre]!=-1) return f[pos][sta][pre];
	int up=limit?a[pos]:9;//判断高位标记
	int tmp=0;
	for (int i=0;i<=up;i++)
	{
		if (pre!=-1&&abs(pre-i)<2) continue;//如果不合法就跳过
		if (i==0&&len==0) tmp+=dfs(pos-1,0,0,-1,limit&&i==a[pos]);
		else
		{
			tmp+=dfs(pos-1,1,i,i,limit&&i==a[pos]);
		}
	}
	if(!limit) f[pos][sta][pre]=tmp;
	return tmp;
}
int solve(int x)
{
	int cnt=0;
	while (x!=0)
	{
		a[++cnt]=x%10;
		x=x/10;
	}
	dfs(cnt,0,0,-1,true);
}
int main()
{
	int n,m;
	scanf("%d%d",&n,&m); 
	memset(f,-1,sizeof(f));
	printf("%d
",solve(m)-solve(n-1));
}

  

原文地址:https://www.cnblogs.com/nibabadeboke/p/11328096.html