1 最后由 cz (2014-10-13 11:42:22) 编辑

主题: Ugly Numbers

n=2^i*3^j*5^k,ijk是自然数。可以得到n序列 1, 2, 3, 4, 5, 6, 8, 9, 10, 12, 15, ...

求此序列第N个数是多少。

一般的人会这样:
把可能的数都算出来,去重,再排序,得到序列
#include<iostream>
#include<algorithm>
#include<set>
using namespace std;
int main()
{
    set<int> s;
    s.insert(1);
    set<int>::iterator it = s.begin();
    //此处使用1600而非1500,是为了防止类似*it*5 > *(++it)*2的情况出现而导致循环结束时较小的丑数仍未插入容器
    while(s.size()<=1600)
    {
        s.insert(*it*2);
        s.insert(*it*3);
        s.insert(*it*5);
        it++;
    }
    int n;
    while(cin>>n&&n)
    {
        it = s.begin();
        int i = n;
        while(--i){
            ++it;
        }
        cout<<"The "<<n<<"th ugly number is "<<*it<<"."<<endl;
    }
    return 0;
}

明白一些的人思路是这个:http://online-judge.uva.es/board/viewto … mp;t=26972
引用原文代码是:

int main(void)
{
   int N;
   while(scanf("%d", &N)){
      if(N <= 0) continue;
      int v, p, temp;
      v = 1; p = 1;
      while(p < N){
         v++;
         temp = v;
         while(temp % 2 == 0) temp /= 2;
         if(temp == 1) { p++; continue;}
         while(temp % 3 == 0) temp /= 3;
         if(temp == 1) { p++; continue;}
         while(temp % 5 == 0) temp /= 5;
         if(temp == 1) { p++; continue;}
      }
      printf("%d\n", v);
   }
   return 0;
}

数小还可以,数大了就会慢了

然后算法更精一些的人还可以这样:http://www.2cto.com/kf/201306/222203.html
引用原文代码是:

#include<stdio.h> 
int main(void)
{
    int un[1505]={0};
    int m2=0,m3=0,m5=0,n,t;
    un[0]=1;
    for(n=1;n<1500;n++)
    {
        if(2*un[m2]>3*un[m3])
            t=un[m3]*3;
        else
            t=un[m2]*2;
        if(t>un[m5]*5)
            t=un[m5]*5;

        if(t == 2*un[m2]) m2++;
        if(t == 3*un[m3]) m3++;
        if(t == 5*un[m5]) m5++;

        un[n]=t;
    }
    printf("The 1500'th ugly number is %d.\n",un[1499]);
    return 0;
}

算法思路就是先定义一个集合,该集合中有元素1,如果x在集合中,并且y是x的下一个丑数,那么x*2,x*3,x*5也在集合中,其它数不再集合中,这三个数中必定是2x最小,因此首先放入数组中,而此时*2最小的应该是x的下一个丑数y*2,此时应该找出y*2,x*3,x*5中最小的数放入数组,以此类推,具体操作如下:

1
*2
*3
*5
选出乘积最小的,加入到结果集中,相应指针右移

1     2
*3   *2
*5
选出乘积最小的,加入到结果集中,相应指针右移

1     2     3
*5   *2
*3
选出乘积最小的,加入到结果集中,相应指针右移

1     2     3     4
*5   *3    *2
选出乘积最小的,加入到结果集中,相应指针右移

1     2     3     4
*3   *2
*5
以此类推,直到获得足够长的结果集
嗯。算是空间换时间吧。目的下标不确定的话需要自己处理数组空间。不过速度与前者比较那是相当的快啊。
不知道还有没有更好的解法。