初探数位DP-hdu2089

一开始刷dp就遇到了数位dp,以前程序设计艺术上看过一点,基本没懂,于是趁今天遇到题目,想把它搞会,但就目前状态来看仍然是似懂非懂啊,以后还要反复搞

统计区间[l,r]的满足题意的数的个数,可以转换成求[0,r]-[0,l),这也是数位dp题的一个明显的提示
F[i,st] 代表 位数为i(可能允许前导0。如00058也是个5位数),状态为st的方案数。这里st根据题目需要确定。
如i=4,f[i,st]也就是0000~9999的符合条件的数的个数(十进制)
决策第i位是多少(such as 0~9)

这里采用的是记忆化搜索的处理方式,有模板

1 int dfs(int i, int s, bool e) {                 //i表示当前的位数,s表示状态,e表示后面位数能否任意填
2     if (i==-1) return s==target_s;              //最后一位取完,找到一个符合条件的值
3     if (!e && ~f[i][s]) return f[i][s];         //之前位数对应要求的值已经确定,在这里就直接返回
4     int res = 0;                                //记录符合条件的值
5     int u = e?num[i]:9;                         //是否能任意填,能任意填则必须小于原来位数上对应的值,否则则可以去到0-9
6     for (int d = first?1:0; d <= u; ++d)        //逐个填充值,通常会在下面继续加上一些条件,排除不需要的值
7         res += dfs(i-1, new_s(s, d), e&&d==u);  //下个位数
8     return e?res:f[i][s]=res;                   //可以任意填的话,说明到i位还未确定res没有包含所有情况,不可以任意填说明后面已经确定,即f也可以确定
9 }

 2015-04-20 模板

 1 int dfs(int p,int s,bool e) {
 2     if(p==-1) return 1;
 3     if(!e &&dp[p][s]!=-1) return dp[p][s];
 4     int res= 0;
 5     int u=e?digit[p]:9;
 6     for (int i=0;i<=u;++i)
 7     {
 8         if(i==4||(s&&i==2))
 9             continue ;
10         res+=dfs(p-1,i==6,e&&i==u);
11     }
12     return e?res:dp[p][s]=res;
13 }
14 int solve(int n)
15 {
16     int len=0;
17     while(n)
18     {
19         digit[len++]=n%10;
20         n/=10;
21     }
22     return dfs(len-1,0,1);
23 }
View Code

 

正确与否有待进一步确认,第一遍看就暂且这么理解吧

f为记忆化数组;

i为当前处理串的第i位(权重表示法,也即后面剩下i+1位待填数);

s为之前数字的状态(如果要求后面的数满足什么状态,也可以再记一个目标状态t之类,for的时候枚举下t);

e表示之前的数是否是上界的前缀(即后面的数能否任意填)。

for循环枚举数字时,要注意是否能枚举0,以及0对于状态的影响,有的题目前导0和中间的0是等价的,但有的不是,对于后者可以在dfs时再加一个状态变量z,表示前面是否全部是前导0,也可以看是否是首位,然后外面统计时候枚举一下位数。

 

今天做了一道基础数位dp题,来自hdu2089
题目大意:给定区间[n,m],求在n到m中没有“62“或“4“的数的个数。
如62315包含62,88914包含4,这两个数都是不合法的。0<n<=m<1000000
那么就用这道题分析一下,首先放个源码
 1 #include <iostream>
 2 using namespace std ;
 3 int f[8][2] ;//f[i][0]:前i位符合要求 f[i][1]:前i位符合要求且i+1位是6
 4 int digit[9] ;//digit[i]表示n从右到左第i位是多少 
 5 int dfs(int i,int s,bool e)//i表示当前位,s表示i位之前的状态,e表示当前位是否可以随意填写 
 6 { 
 7     if(i==0)
 8         return 1 ;
 9     if(!e && f[i][s]!=-1)
10         return f[i][s] ;
11     int res=0 ;
12     int u=e?digit[i]:9 ;
13     for(int d=0 ;d<=u ;d++)
14     {
15         if(d==4 || (s && d==2))
16             continue ;
17         res+=dfs(i-1,d==6,e&&d==u) ;
18     }
19     return e?res:f[i][s]=res ;
20 }
21 int callen(int n)//计算n的长度 
22 {
23     int cnt=0 ;
24     while(n)
25     {
26         cnt++ ;
27         n/=10 ;
28     }
29     return cnt ;
30 }
31 void caldigit(int n,int len)//计算n的digit数组 
32 {
33     memset(digit,0,sizeof(digit)) ;
34     for(int i=1 ;i<=len ;i++)
35     {
36         digit[i]=n%10 ;
37         n/=10 ;
38     }
39 }
40 int solve(int n)//计算[0,n]区间满足条件的数字个数 
41 {
42     int len=callen(n) ;
43     caldigit(n,len) ;
44     dfs(len,0,1) ;
45 }
46 int main()
47 {
48     int n,m ;
49     memset(f,-1,sizeof(f)) ;
50     while(~scanf("%d%d",&n,&m))
51     {
52         if(n==0 && m==0)
53             break ;
54         printf("%d\n",solve(m)-solve(n-1)) ;//用[0,m]-[0,n)即可得到区间[n,m]
55     }
56     return 0 ;
57 }

2015-04-20 二次代码,风格变好了很多

 1 #include<cstdio>
 2 #include<iostream>
 3 #include<algorithm>
 4 #include<cstring>
 5 #include<cmath>
 6 #include<queue>
 7 #include<map>
 8 using namespace std;
 9 #define MOD 1000000007
10 const int INF=0x3f3f3f3f;
11 const double eps=1e-5;
12 #define cl(a) memset(a,0,sizeof(a))
13 #define ts printf("*****\n");
14 const int MAXN=1005;
15 int n,m,tt;
16 int digit[9],dp[8][2];
17 int dfs(int p,int s,bool e) {
18     if(p==-1) return 1;
19     if(!e &&dp[p][s]!=-1) return dp[p][s];
20     int res= 0;
21     int u=e?digit[p]:9;
22     for (int i=0;i<=u;++i)
23     {
24         if(i==4||(s&&i==2))
25             continue ;
26         res+=dfs(p-1,i==6,e&&i==u);
27     }
28     return e?res:dp[p][s]=res;
29 }
30 int solve(int n)
31 {
32     int len=0;
33     while(n)
34     {
35         digit[len++]=n%10;
36         n/=10;
37     }
38     return dfs(len-1,0,1);
39 }
40 int main()
41 {
42     int i,j,k;
43     #ifndef ONLINE_JUDGE
44     freopen("1.in","r",stdin);
45     #endif
46     memset(dp,-1,sizeof(dp));
47     while(scanf("%d%d",&n,&m)!=EOF)
48     {
49         if(n==0&&m==0)
50             break;
51         printf("%d\n",solve(m)-solve(n-1));
52     }
53 }
View Code

 

这里通过输出中间变量来辅助理解

 1 int dfs(int i,int s,bool e)//i表示当前位,s表示i位之前的状态(这里表示是否为6),e表示当前位是否可以随意填写
 2 {
 3     //printf("*****\n");
 4     //printf("--%d %d %d\n",i,s,e);
 5     if(i==0)
 6         return 1 ;      //说明前面的位数已经确定,该方案成立
 7     if(!e && f[i][s]!=-1)
 8     {
 9         //printf("--%d %d %d\n",i,s,e);
10         return f[i][s] ;
11     }
12 
13     int res=0 ;
14     int u=e?digit[i]:9 ;
15     //printf("--%d %d %d %d\n",i,s,e,u);
16     for(int d=0 ;d<=u ;d++)
17     {
18         if(d==4 || (s && d==2))
19             continue ;
20         printf("--%d %d %d %d\n",i,s,e,d);
21         res+=dfs(i-1,d==6,e&&d==u) ;
22     }
23     printf("***************  %d %d %d %d\n",i,s,e,res);
24     return e?res:f[i][s]=res ;
25 }

这里输出了0-200的情况

1 200
--3 0 1 0  //从百位开始计算,之前没有6,所以中间为0,后面可以任意填充所以为1,首先在第一位上填0
--2 0 0 0  //第二位上填0
--1 0 0 0  //第三位上填0,一种情况,res+1,下面一样
--1 0 0 1  //第三位上填1
--1 0 0 2
--1 0 0 3
--1 0 0 5
--1 0 0 6
--1 0 0 7
--1 0 0 8
--1 0 0 9  //第三位上填9
***************  1 0 0 9  //f[1][0]=9,个位上的情况且十位不含6全部确定共9种,下一步之前res重新清零
--2 0 0 1  //十位填2,之后再确定个位,发现个位上的情况已经确定,于是直接返回f[1][0],res+f[1][0]
--2 0 0 2
--2 0 0 3
--2 0 0 5
--2 0 0 6  //十位填6,之后s变为1,个位需要重新确定
--1 1 0 0
--1 1 0 1
--1 1 0 3
--1 1 0 5
--1 1 0 6
--1 1 0 7
--1 1 0 8
--1 1 0 9
***************  1 1 0 8  f[1][1]=8  //个位上十位含6共9种情况
--2 0 0 7  //继续枚举十位
--2 0 0 8
--2 0 0 9
***************  2 0 0 80   //f[2][0]=80
--3 0 1 1  //百位填1  ret+f[2][0]
--3 0 1 2  //百位填2  ret+f[2][0]
--2 0 1 0  //十位填0
--1 0 1 0  //个位填0  ret+1
***************  1 0 1 1  //个位上只能有0
***************  2 0 1 1  //十位上只能有00
***************  3 0 1 161  //返回的是ret
161

正确性有待商榷,待我再多做几道题看看

更多数位dp题可以参见我博客,代码风格基本是统一的

 


 

 

 

 

转载于:https://www.cnblogs.com/cnblogs321114287/p/4260821.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/492567.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

自动驾驶的疑点重重, 再次印证了科技的「非理性繁荣」

来源&#xff1a;悟空智能科技特斯拉 CEO 马斯克对全自动驾驶的短期实现&#xff0c;有着近乎疯狂的执念。最近&#xff0c;他又在第四季度财报的电话会议上表示&#xff0c;特斯拉汽车在今年年底前能实现全自动驾驶&#xff0c;无需人类干预。马斯克还表示&#xff0c;特斯拉在…

Truncated SVD for faster dection

Truncated SVD方法最先被提出在《Fast R-CNN》论文中&#xff0c;用于降低全连接层的运算量&#xff0c;提升模型的速度。在卷积神经网络的分类任务中&#xff0c;FC层的运算速度远远大于CONV层&#xff0c;而在Fast R-CNN的目标检测任务中&#xff0c;大多数的运算时间发生在F…

CSS学习-网页导航栏

用ul制作网页导航栏 <!DOCTYPE html> <html><head><style>ul {list-style-type: none;margin: 0;padding: 0;width: 800px;overflow: hidden;}li {float: left;}a {display: block;width: 120px;font-weight: bold;color: #FFFFFF;border-right: 1px s…

自动驾驶技术如何升级?这份技能图谱为你指路

来源&#xff1a;AI前线自动驾驶技术在过去的一年里发展十分迅速&#xff0c;无论控制系统的升级还是高清地图的泛用&#xff0c;无不在推动自动驾驶的落地。再加上开源框架的进一步成熟&#xff0c;V2X 的落地实践&#xff0c;传感器融合更强等多重因素的影响下&#xff0c;自…

Gradient Descent

梯度下降是我们在训练神经网络时用于训练参数的方法&#xff0c;本文总结了目前常用的几种梯度下降算法&#xff0c;包括原理、公式推导、解决的问题&#xff0c;主要要SGD、Momentum、NAG、AdaGrad、AdaDelta、RMSProp、Adam&#xff0c;先贴上手写的笔记&#xff0c;有时间再…

互联网+检验检测智能化成发展趋势

来源&#xff1a;传感器技术摘要&#xff1a;随着工业自动化技术的迅猛发展&#xff0c;智能检测技术被广泛地应用在工业自动化、化工、军事、航天、通讯、医疗、电子等行业&#xff0c;是自动化科学技术的一个格外重要的分支科学。众所周知&#xff0c;智能检测技术是在仪器仪…

5G、物联网和AI结合的究极形态是什么?一文看尽智能连接在5大领域的12个典型案例!...

来源&#xff1a;IoT Analytics编译&#xff1a;物联网智库摘要&#xff1a;智能连接&#xff08;Intelligent connectivity&#xff09;是一种全新的概念——未来&#xff0c;5G、AI和物联网的融合能够成为加速科技发展的催化剂&#xff0c;并催生出新的颠覆式的数字化服务。基…

10天学安卓-第二天

10天学安卓-第二天 原文:10天学安卓-第二天继续我们的学习。 相信我&#xff0c;第一天的工作是最为重要的&#xff0c;通过这些工作&#xff0c;我们把开发安卓所必须的环境、基础条件都配置好了&#xff0c;相信肯定遇到了很多问题&#xff0c;不过&#xff0c;根据我的经验&…

德国费斯托又双叒叕更新,象鼻子机械臂+超逼真仿生手,比人手都强大

来源&#xff1a;机器人大讲堂编辑&#xff1a;海蛟摘要&#xff1a;在机器人领域&#xff0c;小编最佩服两家公司&#xff0c;一家是波士顿动力&#xff0c;另一家就是费斯托。费斯托这家源自德国的公司以平均每年更新2-3款仿生机器人的速度&#xff0c;扩充着它们的仿生机器人…

微软全球执行副总裁沈向洋:你给自己的定位是什么,你就会得到什么

来源&#xff1a;AI 科技评论摘要&#xff1a;沈向洋&#xff0c;美国国家工程院院士、微软全球执行副总裁、ACM/IEEE Fellow。多年来&#xff0c;沈向洋专注于计算机视觉和计算机图形学的研究&#xff0c;并领导和开发了 Bing 搜索。目前&#xff0c;他是微软公司级别最高的中…

用互联网大脑模型分析5G重点影响的6个科技产业

作者&#xff1a;刘锋 计算机博士&#xff0c;《互联网进化论》作者5G是指第五代移动电话行动近信标准&#xff0c;也称第五代移动通信技术&#xff0c;是4G之后的延伸&#xff0c;其峰值理论传输速度可达每秒数十Gb。对比4G的主要提高如下&#xff1a;5G的速度将达到4G的100倍…

Gartner:2019年十大数据与分析技术趋势

来源&#xff1a;网络大数据近日&#xff0c;全球领先的信息技术研究和顾问公司Gartner指出&#xff0c;增强型分析(augmented analytics)、持续型智能(continuous intelligence)与可解释型人工智能(explainable AI)是数据与分析(data and analytics)技术领域内的主要趋势之一&…

Gearman + Nodejs + MySQL UDF异步实现 MySQL 到 Redis 的数据同步

目录 1, 环境2, Redis简介3, Gearman简介4, MySQL - Redis配合使用方案4, 软件安装5, MySQL UDF Trigger同步数据到Gearman6, 参考资料1, 环境 CentOS, MySQL, Redis, Nodejs 2, Redis简介 Redis是一个开源的K-V内存数据库&#xff0c;它的key可以是string/set/hash/list/...&…

5G风起,四大IoT迎风爆发!智能家居与电表高速增长

来源&#xff1a;智东西摘要&#xff1a;深度剖析智能家居、智能城市、车联网、网联无人机四大领域新机遇。2018年&#xff0c;我国物联网&#xff08;IoT&#xff09;连接数从2017年的15.4亿飙升至30.63亿&#xff0c;几近增长了100%&#xff0c;增速喜人。而在这组数据背后&a…

机器学习基石笔记5——为什么机器可以学习(1)

转载请注明出处&#xff1a;http://www.cnblogs.com/ymingjingr/p/4271742.html 目录 机器学习基石笔记1——在何时可以使用机器学习(1) 机器学习基石笔记2——在何时可以使用机器学习(2) 机器学习基石笔记3——在何时可以使用机器学习(3)(修改版) 机器学习基石笔记4——在何时…

PPT|工业互联网关键技术专利态势

来源&#xff1a;中国信通院CAICT摘要&#xff1a;《工业互联网关键技术专利态势分析&#xff08;2019&#xff09;》对工业互联网的三个重要体系进行深入知识产权分析。以下PPT资料是工业互联网产业联盟和中国信通院团队对《工业互联网关键技术专利态势分析&#xff08;2019&a…

生命简史——跨越地球40亿年

来源&#xff1a;新原理研究所摘要&#xff1a;你一定也曾好奇过&#xff0c;地球上的生命究竟是如何起源和演化的&#xff1f;它又是如何从简单的原核细胞不断地演化成复杂的多细胞&#xff1f;如此多元化的物种是如何进化而成的&#xff1f;每一次变化都历经了怎样的挑战与压…

图论解决复杂路口红绿灯安排,python语言实现

文章目录问题描述说明性描述操作性描述图着色问题图着色算法算法精化和python描述算法细节处理&#xff1a;python实现讨论问题描述 说明性描述 说明性描述说明了需要解决的问题是什么&#xff0c;针对什么样的问题&#xff0c;期望什么样的解 这是一个5条路的交叉口&#x…

从算法到硬件,一文读懂2019年 AI如何演进

来源&#xff1a;图灵TOPIA翻译&#xff1a;黄姗&#xff0c;杨鹏岳在刚刚过去的2018年&#xff0c;人工智能领域的大事件、新发现和新进展层出不穷。BERT重磅发布&#xff0c;刷新了很多NLP的任务的最好性能&#xff1b;GAN相关研究论文持续增长&#xff0c;生成的照片达到了以…

《阿丽塔》脑机接口正从科幻走向现实

来源&#xff1a;zhongcap摘要&#xff1a;《流浪地球》和《阿丽塔》前后脚上映&#xff0c;难免不让人比较一番。科幻片的魅力&#xff0c;在于它试验和想象未来的可能性。昨天晚上小编去看了卡梅隆的新作《阿丽塔&#xff1a;战斗天使》。《流浪地球》和《阿丽塔》前后脚上映…