博客
关于我
手机号码(数位dp-dfs)
阅读量:355 次
发布时间:2019-03-04

本文共 3049 字,大约阅读时间需要 10 分钟。

1. 问题描述:

人们选择手机号码时都希望号码好记、吉利。比如号码中含有几位相邻的相同数字、不含谐音不吉利的数字等。手机运营商在发行新号码时也会考虑这些因素,从号段中选取含有某些特征的号码单独出售。为了便于前期规划,运营商希望开发一个工具来自动统计号段中满足特征的号码数 量。

工具需要检测的号码特征有两个:号码中要出现至少3个相邻的相同数字,号码中不能同时出现8和4。号码必须同时包含两个特征才满足条件。满足条件的号码例如:13000988721、 23333333333、14444101000。而不满足条件的号码例如:1015400080、10010012022。 手机号码一定是11位数,前不含前导的0。工具接收两个数L和R,自动统计出[L,R]区间内所有满足条件的号码数量。L和R也是11位的手机号码。

输入描述:

输入文件内容只有一行,为空格分隔的2个正整数L,R。

10^10 ≤  L ≤  R < 10^11

输出描述:

输出文件内容只有一行,为1个整数,表示满足条件的手机号数量。

示例1

输入
12121284000 12121285550
输出
5
样例解释
满足条件的号码: 12121285000、 12121285111、 12121285222、 12121285333、 12121285550

链接:https://ac.nowcoder.com/acm/problem/19945

来源:牛客网

2. 思路分析:

这道题目与牛客中的题目是类似的,都是数位dp的内容,只是这道题目在数中的位上多了几个限制条件:号码中至少需要3个连续相同的数字,不能同时出现4和8,首位不能够为0。主要还是使用递归来尝试每一位可能的数字,在递归的过程中记录下相关的限制条件对应的变量值。我们可以通过在递归方法中传递参数来记录这些限制条件。递归方法需要传递的参数有:当前递归的位置(从高位开始递归)pos,上一次出现的数字last,最开始出现的数字num,是否出现连续3个相同的布尔型变量ok,到目前位置是否出现4-has4,到当前的位置是否出现了8-has8,一个用来记录是否是最高位的最大数字的变量flag,用来控制下一个低位能够填的数字范围,是[0,9]还是[0,x](在数位dp的递归方法中这个变量感觉是必须的),用来标记当前的位置是否是最高位的first变量。可以声明一个六维的列表(列表的维度对应方法中动态变化的参数(python中创建:逆序创建),记忆型的递归都是类似的都是通过在递归过程中动态变化的参数声明对应维度的数组或者列表,每一维度都有其对应的含义这样可以减少子问题的重复求解,而且在数位dp使用递归解决的时候一般都需要这个记忆型列表来减少递归的时间复杂度。递归的主要思想是使用方法中的flag变量来得到当前位置可以填的数字范围,在递归的过程中更新对应参数的变化,使用六维列表来记录递归过程的结果,当发现当前位置的列表值为之前求解过那么直接返回列表对应的值即可。

3. 代码如下:

python代码:

nums = [0] * 13# 六维列表(创建的时候注意括号的嵌套关系)f = [[[[[[-1] * 2 for i in range(2)] for j in range(2)] for k in range(11)] for l in range(12)] for m in range(13)]# num表示前一个数字, last表示最后一个数字(两个变量主要是计算连续的相同的数字的个数), ok记录是否出现过连续相同的三个数字, have4表示到当前位置是否出现过4,, hava8为是否出现过8, flag用来记录是否是最高位的最大数字, first用来标记是否是第一个位置也即最高位, 最高位不能够为0def dfs(pos: int, last: int, num: int, ok: bool, have4: bool, have8: bool, flag: bool, first: int):    if pos == 0:        return 1 if ok and (not have4 or not have8) else 0    if flag and f[pos][last][num][ok][have4][have8] != -1: return f[pos][last][num][ok][have4][have8]    # 三目运算符    x = 9 if flag else nums[pos]    res = 0    for i in range(0, x + 1):        # 第一个数字不能够为0        if i == 0 and first: continue        res += dfs(pos - 1, i, last, ok or (i == last and i == num), have4 or i == 4, have8 or i == 8, flag or i < x, 0)    if flag:        f[pos][last][num][ok][have4][have8] = res    return resdef cal(x: int):    pos = 1    while x:        nums[pos] = x % 10        x //= 10        pos += 1    return dfs(pos - 1, 0, 0, False, False, False, False, 1)if __name__ == '__main__':    l, r = map(int, input().split())    # cal(r)计算[0:r]满足条件的数目, cal(l - 1)计算[0:l - 1]满足条件的数目    print(cal(r) - cal(l - 1))

大佬的c++代码:

//记录最后出现的数字是几 上一位是几 是否已经有三连号 有没有出现8 有没有出现4#include 
using namespace std;#define int long longint f[13][11][13][2][2][2];int a[13];int dp(int pos,int num,int last,bool ok,bool have8,bool have4,bool flag,bool first){ if(pos==0) return ok&&((!have8)||(!have4)); if(flag&&f[pos][num][last][ok][have8][have4]!=-1) return f[pos][num][last][ok][have8][have4]; int x=flag?9:a[pos]; int ans=0; for(int i=0;i<=x;i++) { if(first&&i==0) continue; ans+=dp(pos-1,i,num,ok||(i==num&&i==last),have8||i==8,have4||i==4,flag||i

 

转载地址:http://ucwg.baihongyu.com/

你可能感兴趣的文章
11.2.6 时间值的小数秒
查看>>
11.2.7 日期和时间类型之间的转换
查看>>
附录 B 错误信息和常见问题
查看>>
redis 内存溢出_从数据存储的角度告诉你Redis为什么这么快!
查看>>
实例分析Facebook激励视频广告接入
查看>>
实例:使用OKGO下载网络压缩包资源,然后解压缩放在本地使用
查看>>
Android主题和样式精炼详解
查看>>
HDFS Missing Block诊断信息的改进
查看>>
解决mybatis嵌套查询使用PageHelper分页不准确
查看>>
Redis源码分析(七)--- zipmap压缩图
查看>>
大规模集群自动化部署工具--Chef的安装部署
查看>>
一致性哈希算法
查看>>
HDFS源码分析(六)-----租约
查看>>
自定义Hive Sql Job分析工具
查看>>
聊聊HDFS RBF第二阶段的主要改进
查看>>
公司如何使用开源软件
查看>>
【MySQL】(九)触发器
查看>>
关于Altium Designer 09导出BOM表不能正确分类问题
查看>>
Oracle 11G环境配置
查看>>
【Spark】(六)Spark 运行流程
查看>>