HDOJ 1058 Humble Numbers解题报告【DP】
2013-07-30 21:16
357 查看
Humble Numbers
转载请注明出处http://blog.csdn.net/liangbopirates/article/details/9632829
题目详见http://acm.hdu.edu.cn/showproblem.php?pid=1058
开始拿到这个题目的时候还纠结了半天,英语很差的话这个题是不可能AC的。。而我就是其中之一。。。
Humber Number不用管它啥意思,就是一类定义的数而已。如果一个数的质因数(素因数)仅仅是2、3、5 or 7的话那就被称为Humber Number。特殊的1也在其列。而且题目给出了前20个Humber Number。1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 12, 14, 15, 16, 18, 20, 21, 24, 25, 27。注意仅仅二字,11包含质因数11,26包含质因数13都不在其列。编写程序求第n个Humble Number。输入输出格式要搞明白。
OK,搞清了题意,那就来分析一下。这个题的意思很清楚明了,就是给你一个N,求出第N个Humble Number。如何求?一开始我想到遍历,可是觉得很麻烦,估计会很超时。我就想啊,既然是2 3 5 7 ,我用1和他们相加如何?得到了3 4 6 8,这些数肯定是Humble Number。可是如何继续下去呢?用3和2 3 5 7相加?得到 5 6 8 10,还要用4和他们相加?继续下去?感觉很繁琐,就像是一颗树4叉树一样。
所以我放弃了这个思路,又开始想遍历,如果我知道了某个数是不是Humble Number,那我不就可以统计第N个了吗?从1开始遍历,如果i是Humble Number,那我就nums++,知道nums和你给定的N相等我们就求出了。。如何判断一个数是不是Humble Number呢?Humble Number的质因数只能是2 3 5 7 ,被这些数分别整除后结果肯定是1,而且整除次数最多是Number/2.
OK,上代码
#include <iostream> using namespace std; //查看n是不是Humble Number int IsHumbleNumber(long int n); int main() { long int nums; long int number; long int i; while(cin>>number) { if(0==number) break; nums=0; //初始化 记录有多少个HumbleNumber for(i=1;;i++) { if(IsHumbleNumber(i)) nums++; if(number==nums) break; } //此时i的值就是第number个humble number //输出格式//// if((number>=4)&&(number<=20)) cout<<"The "<<number<<"th humble number is "<<i<<endl; //英语差了这个题别想AC了。。。 else if(1==(number-(number/10)*10)) cout<<"The "<<number<<"st humble number is "<<i<<endl; else if(2==(number-(number/10)*10)) cout<<"The "<<number<<"nd humble number is "<<i<<endl; else if(3==(number-(number/10)*10)) cout<<"The "<<number<<"rd humble number is "<<i<<endl; else cout<<"The "<<number<<"th humble number is "<<i<<endl; } return 0; } //查看n是不是Humble Number int IsHumbleNumber(long int n) { //long int num=1; if(n==1) //1 is Humble Number return true; long int num=n; long int i; for(i=1;i<=num/2;i++) { if(n%2==0) n/=2; else if(n%3==0) n/=3; else if(n%5==0) n/=5; else if(n%7==0) n/=7; } if(n==1) return true; else return false; }
提交之后发现超时,时间复杂度是Humber(N),这个N如果是5842,那么Humber(N)=20亿,超时是必然的结果。而且每次给定的N,都要从头来过。这让我想到了数组,用一个数组把所有的全部存起来,会不会好一些呢? 代码
#include <iostream> using namespace std; //查看n是不是Humble Number int IsHumbleNumber(int n); int main() { int nums; int number; long int i; int j; long int humble[5843]={0};//0位不用 for(j=1;j<=5842;j++) { for(i=humble[j-1]+1;;i++) { if(IsHumbleNumber(i)) break; } humble[j]=i;//此时i的值就是第j个humble number } while(cin>>number) { if(0==number) break; //输出格式//// if((number>=4)&&(number<=20)) cout<<"The "<<number<<"th humble number is "<<humble[number]<<endl; //英语差了这个题别想AC了。。。 else if(1==(number-(number/10)*10)) cout<<"The "<<number<<"st humble number is "<<humble[number]<<endl; else if(2==(number-(number/10)*10)) cout<<"The "<<number<<"nd humble number is "<<humble[number]<<endl; else if(3==(number-(number/10)*10)) cout<<"The "<<number<<"rd humble number is "<<humble[number]<<endl; else cout<<"The "<<number<<"th humble number is "<<humble[number]<<endl; } return 0; } //查看n是不是Humble Number int IsHumbleNumber(int n) { //long int num=1; if(n==1) //1 is Humble Number return true; int num=n; int i; for(i=1;i<=num/2;i++) { if(n%2==0) n/=2; else if(n%3==0) n/=3; else if(n%5==0) n/=5; else if(n%7==0) n/=7; } if(n==1) return true; else return false; }
NO,还是超时!因为整个求Humber Number的过程是Humber(5842),也就是20亿,肯定会超时啦。。。所以来说,这个是行不通的。前100个还是很好求的,后面就不行了。 逼不得已放弃这个思路。看这个20亿,我觉得时间复杂度可不可以是和N相关的和Humber Number没关系,O(N)?可以不? 想一想开始时候的想法,4叉树,必然有很多相同的节点,那么这就是重叠子问题?而且求第N个Humber Number是和第N-1个Humber Number有关系的?也就是说问题的最优解可以用子问题的最优解来解决,这不是传说中的DP吗? OK,有点兴奋,怎么做?如何得到表达式?用第一次的思路,用加不行,可以用乘吗?1*2,1*3,1*5,1*7?得出的结果怎么办?所有的数还要和 2 3 5 7相乘,这不是和用加是一样的吗?绞尽脑汁,终于发现了一点规律了,一开始用1相乘的结果中最小值的就是2,这就是第2个Humber Number。然后呢?如果用2和2 3 5 7 相乘得到最小值是4,唉,不是3啊。可是如果2和2相乘 而3 5 7 还是和1相乘,那最小值不就是3了。YES!这是个规律。此时得到了2 3 ,如果用2和2相乘,3和2相乘,5 7 和1相乘,那么最小值就是4,OK,我发现新大陆了。。 这个表达式好像就是用2 3 5 7和已经得到的Humber Number相乘啊。 继续找规律,得到了4,那么如何得到5?3和2相乘,2和3相乘,1和5相乘,1和7相乘最小值就是5。和2 3 5 7 相乘的数就是之前的Humber Number,可是是哪个呢?根据刚才的规律我我们可以判断的是,一开始1,如果这个数和2 3 5 7 中的一个相乘得到的结果是最小值,那么就往后推一个Humber Number,也就是Humber数组的i++。如果有重复的都给他++。 得到状态转移方程 humble[i]=FMin(humble[p2]*2,humble[p3]*3,humble[p5]*5,humble[p7]*7); 编码
#include <iostream> using namespace std; //求所有的Humble Number void HumbleNumber(long int humble[],int n); long int FMin(long int m,long int n,long int k,long int l); int main() { int nums; int number; long int humble[5843]; HumbleNumber(humble,5842); while(cin>>number) { if(0==number) break; //输出格式//// if((number>=4)&&(number<=20)) cout<<"The "<<number<<"th humble number is "<<humble[number]<<"."<<endl; //英语差了这个题别想AC了。。。 else if(1==(number-(number/10)*10)) cout<<"The "<<number<<"st humble number is "<<humble[number]<<"."<<endl; else if(2==(number-(number/10)*10)) cout<<"The "<<number<<"nd humble number is "<<humble[number]<<"."<<endl; else if(3==(number-(number/10)*10)) cout<<"The "<<number<<"rd humble number is "<<humble[number]<<"."<<endl; else cout<<"The "<<number<<"th humble number is "<<humble[number]<<"."<<endl; } return 0; } //求所有的Humble Number void HumbleNumber(long int humble[],int n) { int i; int p2,p3,p5,p7; p2=p3=p5=p7=1; humble[1]=1; for(i=2;i<=n;i++) { humble[i]=FMin(humble[p2]*2,humble[p3]*3,humble[p5]*5,humble[p7]*7); if(humble[i]==humble[p2]*2)//不用else if 为了重复的 p2++; if(humble[i]==humble[p3]*3) p3++; if(humble[i]==humble[p5]*5) p5++; if(humble[i]==humble[p7]*7) p7++; } } long int FMin(long int m,long int n,long int k,long int l) { long int min1,min2; if(m<=n) min1=m; else min1=n; if(k<=l) min2=k; else min2=l; if(min1<=min2) return min1; else return min2; }
时间复杂度是O(N),就是在5842次就可以全部求出了,然后给定的N就可以O(1),得到结果了。很不错的算法。没有超时,nice!可是结果错误,我那个迷茫啊,彷徨啊。。可是仅仅发现输出结果少了一个尾号”.”,我赶紧添上,又是失败,看来不是这个问题,再说这也该是格式错误的提示啊。。 最后我查了资料才发现,这个英语真心坑啊,看来不是4-20是th,判断的时候不仅仅是最后一位,还和最后两位有关系啊。。真心跪了。。 最后一次提交!!!
#include <iostream> using namespace std; //求所有的Humble Number void HumbleNumber(long int humble[],int n); long int FMin(long int m,long int n,long int k,long int l); int main() { int nums; int number; long int humble[5843]; HumbleNumber(humble,5842); while(cin>>number) { if(0==number) break; //输出格式//// if((1==number%10)&&(11!=number%100)) cout<<"The "<<number<<"st humble number is "<<humble[number]<<"."<<endl; else if((2==number%10)&&(12!=number%100)) cout<<"The "<<number<<"nd humble number is "<<humble[number]<<"."<<endl; else if((3==number%10)&&(13!=number%100)) cout<<"The "<<number<<"rd humble number is "<<humble[number]<<"."<<endl; else cout<<"The "<<number<<"th humble number is "<<humble[number]<<"."<<endl; } return 0; } //求所有的Humble Number void HumbleNumber(long int humble[],int n) { int i; int p2,p3,p5,p7; p2=p3=p5=p7=1; humble[1]=1; for(i=2;i<=n;i++) { humble[i]=FMin(humble[p2]*2,humble[p3]*3,humble[p5]*5,humble[p7]*7); if(humble[i]==humble[p2]*2)//不用else if 为了重复的 p2++; if(humble[i]==humble[p3]*3) p3++; if(humble[i]==humble[p5]*5) p5++; if(humble[i]==humble[p7]*7) p7++; } } long int FMin(long int m,long int n,long int k,long int l) { long int min1,min2; if(m<=n) min1=m; else min1=n; if(k<=l) min2=k; else min2=l; if(min1<=min2) return min1; else return min2; }
成功!!鲜红的Accepted,很有成就感啊。 总的来说这个题是不难的,只要用心去想肯定可以AC,这也算是很简单的DP啦。不得不吐槽的是和英语太有关系了。。。
转载请注明出处http://blog.csdn.net/liangbopirates/article/details/9632829
相关文章推荐
- HDOJ 1058:Humble Numbers 寻找丑数问题 解题报告
- hdoj 1058 Humble Numbers(dp)
- HDOJ---1058 Humble Numbers[DP]
- hdoj 1058 Humble Numbers【dp】
- HDOJ1058 Humble Numbers DP简单题
- HDOJ1058(Humble Numbers)dp
- HDOJ(HDU).1058 Humble Numbers (DP)
- HDOJ-----1058---Humble Numbers(DP)
- hdoj1058_Humble Numbers(dp)
- hdoj-1058-Humble Numbers【DP&】
- 寻找丑数问题 HDOJ 1058 Humble Numbers
- hdu 1058 Humble Numbers(dp)
- hdu 1058 Humble Numbers(dp)
- 【HDOJ】1058 Humble Numbers
- HDOJ 1058 - Humble Numbers 更新Treap模板..
- HDU 1058Humble Numbers(dp)
- 【HDU】1058 - Humble Numbers(dp)
- hdu 1058:Humble Numbers(动态规划 DP)
- HDOJ 1058 Humble Numbers
- HDU 1058 Humble Numbers (DP)