九度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 ****************************************************************/