1. 程式人生 > >九度OJ-題目1214:醜數

九度OJ-題目1214:醜數

題目連結地址:

題目描述:
把只包含因子2、3和5的數稱作醜數(Ugly Number)。例如6、8都是醜數,但14不是,因為它包含因子7。
習慣上我們把1當做是第一個醜數。求按從小到大的順序的第N個醜數。

輸入:
輸入包括一個整數N(1<=N<=1500)。

輸出:
可能有多組測試資料,對於每組資料,
輸出第N個醜數。

樣例輸入:
3

樣例輸出:
3

解題思路:

這道題我的想法是從2開始依次遍歷每個整數,如果某個整數只包含因子2、3和5,就可以認為它是醜數,這個方法顯然太暴力了,肯定會超時的。於是上網搜了一下此題的解法,發現網上的解法都大致一樣:因為除1之外,後面的醜數都只包含2,3,5這3個因子,可以由2,3,5這3個因子與已有的醜數相乘推算出新的醜數。以下是推算的具體過程:
  (1) 根據3個因子將候選醜數分成3類:由與2相乘得到的候選醜數,由與3相乘得到的候選醜數,由與5相乘得到的候選醜數;
  (2) 每次都從這3類候選醜數中選擇一個最小值做為新的醜數,並且更新相應類的候選醜數。
舉個栗子,以下是求第7個醜數的過程:
    1) 第1個醜數是1;
    2) 將2,3,5分別與第1個醜數1相乘,此時候選醜數是{2,3,5},所以第2個醜數是2,此時醜數序列為[1,2];
    3) 將2與第2個醜數2相乘得4;3,5分別與第1個醜數1相乘,此時候選醜數是{4,3,5},所以第3個醜數是3,

           此時醜數序列為[1,2,3];
    4) 將2與第2個醜數2相乘得4,將3與第2個醜數2相乘得6,將5與第1個醜數1相乘得5,此時候選醜數是{4,6,5},

           所以第4個醜數是4,此時醜數序列為[1,2,3,4];
    5) 將2與第3個醜數3相乘得6,將3與第2個醜數2相乘得6,將5與第1個醜數1相乘得5,此時候選醜數是{6,6,5},

           所以第5個醜數是5,此時醜數序列為[1,2,3,4,5];
    6) 將2與第3個醜數3相乘得6,將3與第2個醜數2相乘得6,將5與第2個醜數2相乘得10,此時候選醜數是{6,6,10},

           所以第6個醜數是6,此時醜數序列為[1,2,3,4,5,6];
     7) 將2與第4個醜數4相乘得8,將3與第3個醜數3相乘得9,將5與第2個醜數2相乘得10,此時候選醜數是{8,9,10},

            所以第7個醜數是8,此時醜數序列為[1,2,3,4,5,6,8]。
AC程式碼如下:

#include<stdio.h>
#define MAX 1501
 
/**
* 返回3個數中的最小值
* @param long long a  第一個數
* @param long long b  第二個數
* @param long long c  第三個數
* @return long long  三個數中的最小值
*/
long long getMinOfThreeNumbers(long long a,long long b,long long c)
{
  long long min = a;
  if(b < min)
     min = b;
  if(c < min)
     min = c;
  return min;
}
 
/**
* 獲取前n個醜數
* @param longlong uglyNumber[] 用於存放醜數的陣列
* @return void;
*/
void getUglyNumbers(long long uglyNumber[],int n)
{
   int i;
   int indexOfUglyNumber = 1;          // 醜數陣列對應的下標
   int indexOfTwo = 1;                 // 與2對應的乘數的在醜數陣列中的下標
   int indexOfThree = 1;               // 與3對應的乘數的在醜數陣列中的下標
   int indexOfFive = 1;                // 與5對應的乘數的在醜數陣列中的下標
   long long curUglyNumber;            // 當前生成的醜數
   long long curUglyNumberOfTwo;       // 由與2相乘得到的醜數
   long long curUglyNumberOfThreee;    // 由與3相乘得到的醜數
   long long curUglyNumberOfFive;      // 由與5相乘得到的醜數
   uglyNumber[1] = 1;                  // 第1個醜數是1
   for(i = 2;i <= 1500; i++)
   {
      curUglyNumberOfTwo = 2 * uglyNumber[indexOfTwo];
      curUglyNumberOfThreee = 3 * uglyNumber[indexOfThree];
      curUglyNumberOfFive = 5 * uglyNumber[indexOfFive];
      // 從當前3個候選中,選擇最小的一個做為新的醜數
      curUglyNumber = getMinOfThreeNumbers(curUglyNumberOfTwo,curUglyNumberOfThreee,curUglyNumberOfFive);
      uglyNumber[++indexOfUglyNumber] = curUglyNumber;
      // 更新各個乘數的下標
      while(2 * uglyNumber[indexOfTwo] <= curUglyNumber)
      {
          indexOfTwo++;
      }
      while(3 * uglyNumber[indexOfThree] <= curUglyNumber)
      {
          indexOfThree++;
      }
      while(5 * uglyNumber[indexOfFive] <= curUglyNumber)
      {
          indexOfFive++;
      }
 
   }
}
 
/**
*  列印第n個醜數
*  @param long long uglyNumber[]  儲存醜數的陣列
*  @param int n  n表示列印第n個醜數
*  @return void
*/
void printNthUglyNumber(long long uglyNumber[],int n)
{
   printf("%lld\n",uglyNumber[n]);
}
 
int main()
{
    long long uglyNumber[MAX];             // 存放醜數
    int n;
    getUglyNumbers(uglyNumber,1500);       // 獲取前1500個醜數
    while(EOF != scanf("%d",&n))
    {
       printNthUglyNumber(uglyNumber,n);
    }
    return 0;
}
 
/**************************************************************
    Problem: 1214
    User: blueshell
    Language: C++
    Result: Accepted
    Time:10 ms
    Memory:1020 kb
****************************************************************/