动态规划 求第 n 个 Humble Number(丑数)
2018-03-23 01:35
267 查看
题目:
质因数分解是将一个数分解为若干个质数相乘的形式,这些因数可以重复。比如 30 = 2×3×5,20 = 2×2×5,81 = 3×3×3×3。现在我们将质因数分解之后只出现 2,3,5,7 的数称为 Humble Number,则 20,30,81 均为
Humble Number,而 11,22 不是。前 20 个 Humble Number 的序列为 1,2,3,4,5,6,7,8,9,10,12,14,15,16,18,
20,21,24,25,27。设计一个动态规划算法,求解第 n 个 Humble Number。
优化子结构及子问题重叠性
思考:动态规划问题的关键在于找到优化子结构,子结构的形式并不统一,另外个人认为同时还要考虑从子问题的重叠性来考虑,对于这题灵感就来源于子问题的重叠性。设需要判断M是否为Humble Number,而且已经知道M之前所有的Humble Number,记为Humble_Number_Before_M,注意这是个数组。
首先,考虑的方向是如果知道Humble_Number_Before_M,那么,如何利用Humble_Number_Before_M(子问题)来判断M是否也是Humble Number,找出当前问题(数M)和子问题(Humble_Number_Before_M)的关系(优化子结构),问题就迎刃而解了。这个关系(优化子结构)并不一定是像“最长公共子序列”那样的递推关系式,但是,优化子结构的核心是:
“如果优化问题的解可以通过它的一系列子问题的解构造得到,则称该优化问题具有优化子结构”(P58)
--摘自《算法设计与分析》骆吉洲
那么数M可不可以利用它之前的Humble Number来求解(肯定不是指蛮力)呢?要知道,如果不能,那么只能是蛮力法,需要从1遍历到M/2来判断M中是否包含其他非2,3,5,7的因子,则当前的时间复杂度为O(M/2)。
之前提到灵感来源于:考虑子问题的重叠性来源于哪里。我们知道,如果M(M>=7)是一个Humble Number,那么它的所有因子一定都来源于Humble_Number_Before_M(反证:如果M是Humble Number,且它的某个因子不在Humber_Number_Before_M中,那么与M是Humble Number 矛盾(Humble Number的定义))。例如,675是Humble Number,4725=625*7也是Humble Number,我们之前可能通过某种手段求出675是Humble Number,现在要判断4725是不是Humble Number还需要一步步先判断675是不是Humble Number吗?
分析到这,我们再多花点时间,一定能发现问题的关键之处。我们发现如果M满足:
M%2=0 AND M/2 IN Humble_Number_Before_M
或者
M%3=0 AND M/3 IN Humble_Number_Before_M
或者
M%5=0 AND M/5 IN Humble_Number_Before_M
或者
M%7=0 AND M/7 IN Humble_Number_Before_M
那么,M一定也是Humble Number(答案都给了,自己想),这样我们就充分利用了当前问题的子结构构造当前问题的解。
对于Humble_Numble_Before_M,我们可以使用关联容器Set(C++)进行存储,可以实现高效查找。下面是伪代码。define Set<int> Hash_Humble_Number(简写为HHN) //key值保存已经求出的所有Humble Number
HHN={1,2,3,4,5,6,7} //初始化前7个Humble Number
int Humble_Numer_N; //记录第n个Humble Number
index=8 //记录第index个Humble Number
i=8 //开始从i向后遍历
while(index<=n) Do
If ( (i%2=0 && HHN.find(i/2) = HHN.end()) //未找到key为i的元素,C++ set写法
|| (i%3=0 && HHN.find(i/3) = HNN.end())
|| (i%5=0 && HHN.find(i/5) = HNN.end())
|| (i%7=0 && HHN.find(i/7) = HNN.end())
) Then
HHN.insert(i); //插入第index个Humble Number i
Humble_Numer_N=i; ++index; //目前已经求到第index个
++i //依次遍历,直到index=n,即找到第n个Humble Number
Return Humble_Numer_N
时间复杂度
从伪代码中可以看出,循环结束的条件是找到第n个Humble Number M,那么时间复杂度为:T(n)=O(M)
总结
如果一开始就看代码,可能看不出来这是动态规划,但是如果从头去想去做就能很清楚的知道。这大概就是看人家的代码和自己写代码的区别吧。把握问题的关键点,每一个程序都可能是动态规划。相关文章推荐
- 丑数(humble number) hdu 1058 DP
- Humble Number 丑数和丑代码
- HDU Problem D [ Humble number ]——基础DP丑数序列
- Ugly Number II(求第N个丑数)
- Humble Numbers HDU杭电1058【动态规划】
- LeetCode OJ:Ugly Number(丑数)
- The number of divisors(约数) about Humble Numbers
- hdu 1058:Humble Numbers(动态规划 DP)
- hdu1492 The number of divisors(约数) about Humble Numbers
- HDOJ 1058:Humble Numbers 寻找丑数问题 解题报告
- The number of divisors(约数) about Humble Numbers
- hdu 1492 The number of divisors(约数) about Humble Numbers (数学:排列组合)
- 寻找丑数,把只包含因子2、3和5的数称作丑数(Ugly Number)
- HDU 1492 The number of divisors(约数) about Humble Numbers(数论题目要知道定理呀....)
- HDU 1492 The number of divisors(约数) about Humble Numbers(数学题)
- Humble Numbers(丑数) 超详解!
- hdu1058 Humble Numbers(丑数) —— dp
- LeetCode Ugly Number II(丑数的计算)
- POJ 2247 Humble Numble(我的水题之路——丑数2,3,5,7)
- zoj 1095 Humble Numbers(丑数+dp)