POJ 1338 Ugly Numbers(我的水题之路——丑数2,3,5,质因子组成数)

Ugly Numbers
Time Limit: 1000MS Memory Limit: 10000K
Total Submissions: 15393 Accepted: 6813

Description

Ugly numbers are numbers whose only prime factors are 2, 3 or 5. The sequence 
1, 2, 3, 4, 5, 6, 8, 9, 10, 12, ... 
shows the first 10 ugly numbers. By convention, 1 is included. 
Given the integer n,write a program to find and print the n'th ugly number. 

Input

Each line of the input contains a postisive integer n (n <= 1500).Input is terminated by a line with n=0.

Output

For each line, output the n’th ugly number .:Don’t deal with the line with n=0.

Sample Input

1
2
9
0

Sample Output

1
2
10

Source


一种数字叫丑数,它的所有质因子只有2、3、5组成,现在给一个数字i,问,第i个丑数的值是多少

这道题集训的时候做过,但是是用的几个连续并联判断做的,现在用一个循环下标进行优化,看上去更简便,实际上是一样的。
需要做这一题先要分析丑数的性质。丑数分解之后是2、3、5的垒乘,即是说,所有的丑数都是用i个2、j个3、k个5 相乘得到的(i,j,k均为自然数)。那么,对于一个丑数、乘以2、3、5的结果也一定是丑数。所以,我们让2、3、5,都从1开始乘,求出其结果最小的数字,为第二丑数,即为2,由1*2得到,同理得到了3,5均为丑数。但是我们发现4是由2*2得到的,就是说,是由第二个丑数和2相乘得到。
那么我们可以发现,2这个质因数下一次生成丑数的时候,是从第二丑数开始相乘,而不是第一个,则,我们现在定义一个数组at[3],分别表示2、3、5上一次形成丑数的丑数下标,那么我们下一次就可以直接用上一个丑数下标的值去乘以这个质因子,得到一个新的丑数。
所以我们定义另一个数组ugly[1500],用于存储前1500个丑数,所以当前有,ugly[0] = 1, ugly[1] = 2, ugly[2] = 3, ugly[3] = 4,同时定义一个用于存放质因子的数组factor[3] = {2,3,5}。因为我们需要得到第i个丑数,所以在生成丑数的过程中,我们最好让所有的丑数由大到小排列,所以每一次我们都选取一个下一个生成的最小丑数为下一个丑数,比如之前我们已经生成了,1,2,3,4,5,那么我们用三个质因子生成的下一个丑数分别是,ugly[2] * 2,ugly[1] * 3,ugly[1] * 5,计算可知,这三个中最小的下一个丑数为6,可以由ugly[2] * 2,ugly[1]*3得到。 即用minid表示生成的最小丑数为ugly[at[minid]] * factor[minid],即minid为0或1,表示factor中的下标,且同时得到最小的丑数赋值给ugly的下一个下标ugly[top]。
之后,我们更新,三个质因子的下一次更新丑数的位置,将乘积等于ugly[top]的所有下标+1.
运用以上方法,知道找到需要的所有丑数。

代码(1AC):
#include <cstdio>
#include <cstdlib>
#include <cstring>

int at[3];
int factor[3] = {2, 3, 5};
int ugly[1550];

int main(void){
    int i, j;
    int minid;
    int top;
    int id;

    at[0] = at[1] = at[2] = 0;
    ugly[0] = 1;
    for (top = 1; top < 1550; top++){
        minid = 0;
        for (i = 1; i < 3; i++){
            if (ugly[at[minid]] * factor[minid] >= ugly[at[i]] * factor[i]){
                minid = i;
            }
        }
        ugly[top] = ugly[at[minid]] * factor[minid];
        for (i = 0; i < 3; i++){
            if (ugly[top] == ugly[at[i]] * factor[i]){
                at[i] ++;
            }
        }
    }

    while (scanf("%d", &id), id != 0){
        printf("%d\n", ugly[id - 1]);
    }
    return 0;
}


  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值