数学算法:poweroj1026-丑数(根据固定倍数得到从小到大的序列)

来源:互联网 发布:linux解压文件命令 编辑:程序博客网 时间:2024/05/16 19:21
题目:
1026: 丑数
Time Limit: 1000 MS Memory Limit: 65536 KB
Total Submit: 257 Accepted: 112 Page View: 1467
Submit Status Discuss
Description
丑数就是这个数的质因子只有2,3,5,7这四个,除此之外不再含有其它
别的质因子。

注意1也被认为是丑数.丑数的前20个为
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 12, 14, 15, 16, 18, 20, 21, 24, 25, 27, ... ;
Input
每行输入一个N,1 <= N <= 5842,N为0时输入结束.
Output
输出相应的第N个丑数.
Sample Input
Raw
1
2
3
4
11
12
13
21
22
23
100
1000
5842
0
Sample Output
Raw
1
2
3
4
12
14
15
28
30
32
450
385875
2000000000
Source
SWUST




解题心得:
1、一开始想的是用一个数多次除尽2、3、5、7,最后能够得到1则是丑数,后来想了想,只要用1不停的乘上2、3、5、7就可以得到丑数,但是题目是对于第几个丑数的提问,所以我们需要对于得到的丑数进行一个排序,去重。但是由于数据量比较大,这样明显是不行的。所以需要在去重、排序的部分进行优化。
2、怎么优化呢,这里有一个很神奇的操作,就是把已经排好序的一个丑数列(这里直接用的1),(用1)乘上2、3、5、7,找出乘积中最小的,排在数列的最后面,然后再将之前选中的最小的那个数在数列中的位置向后移动一位,因为我们每次都是将最小的那个数放进数列之中,所以乘上2、3、5、7的部分和数列的最后一个相比只会等于或者大于它,等于的直接在位置中向后移动一位,大于的找出最小的放入,最后得到的就是一个有序的数列。


#include<bits/stdc++.h>using namespace std;long long Min(long long p1,long long p2,long long p3,long long p4){    long long temp1,temp2;    temp1 = min(p1,p2);    temp2 = min(p3,p4);    return min(temp1,temp2);}int main(){    int num[6000];    num[1]= 1;    long long p1=1,p2=1,p3=1,p4=1;    int cnt = 1;    while(cnt<=5842)    {//这里是核心算法,注意不能将if写成else if的形式,因为可能出现和最后一位重合的部分需要直接向后移动一位,也就是去重        long long v = Min(num[p1]*2,num[p2]*3,num[p3]*5,num[p4]*7);        if(v == num[p1]*2)            p1++;        if(v == num[p2]*3)            p2++;        if(v == num[p3]*5)            p3++;        if(v == num[p4]*7)            p4++;        num[++cnt] = v;    }    long long N;    while(scanf("%lld",&N) && N)        printf("%d\n",num[N]);}