問題描述編程
醜數是其質因子只多是2,3或5的數。前10個醜數分別爲1, 2, 3, 4, 5, 6, 8, 9, 10, 12。輸入一個正整數n,求第n個醜數。數組
輸入格式less
每行爲一個正整數n (n <= 1500),輸入n=0結束。spa
輸出格式指針
每行輸出一個整數,表示求得的第n個醜數。three
輸入樣例ip
1input
2string
50io
0
輸出樣例
1
2
243
根據醜數的定義,醜數從小到大排列的序列中的一個數應該是其前面某個數乘以二、3或者5的結果。所以,能夠定義一個數組num[1501]來順序保存序列中的醜數,數組裏面的每個元素的值是前面的某個元素值乘以二、3或者5獲得。
問題的關鍵是怎樣確保數組裏面的各元素是按值的大小依次生成的。
假設數組中已經有若干個序列中的元素,排好序後存在數組中。把序列中現有的最大的數記作M。因爲序列中的下一個數確定是前面某一個數乘以二、3或者5的結果。首先考慮把已有的每一個數乘以2。在乘以2的時候,能獲得若干個結果小於或等於M的。因爲數組中的元素是按照順序生成的,小於或者等於M的數確定已經在數組中了,不需再次考慮;還會獲得若干個大於M的結果,但只須要第一個大於M的結果,由於數組中的元素是按值從小到大順序生成的,其餘更大的結果能夠之後再說,記下獲得的第一個乘以2後大於M的數M2。一樣,把已有的每個數乘以3和5,記下獲得的第一個大於M的結果M3和M5。那麼,序列中下一個數應該是M二、M3和M5三個數的最小者。
事實上,上面所說的把數組中已有的每一個數分別都乘以二、3和5,是不須要的,由於已有的數是按順序存在數組中的。對乘以2而言,確定存在某一個數T2,排在它以前的每個數乘以2獲得的結果都會小於已有最大的數,在它以後的每個數乘以2獲得的結果都會太大。所以,只須要記下這個數的位置P2,同時每次生成一個新的序列中的數的時候,去更新這個P2。對乘以3和5而言,存在着一樣的P3和P5。
定義變量index保存當前待生成的數在序列中的序號,顯然,已生成的序列中的最大元素爲Num[curIndex-1]。
定義3個指針變量int *p2,*p3,*p5;分別指向數組中的3個元素,排在所指元素以前的每個數乘以2(或三、或5)獲得的結果都會小於已有最大的數num[index-1],在所指元素以後的每個數乘以2(或三、或5)獲得的結果都會太大。
初始時,num[1] = 一、index =二、p2 = p3 = p5 = &num[1]。
生成第index個元素的方法爲:
if (*p2 * 2<*p3 * 3) min = *p2 * 2;
else min= *p3 * 3;
if (min> *p5 * 5) min=*p5 * 5;
num[index] = min;
第index個元素生成後,須要對指針p二、p3和p5進行更新,更新方法爲:
if(num[index]==*p2*2) p2++;
if(num[index]==*p3*3) p3++;
if(num[index]==*p5*5) p5++;
#include <stdio.h>
#include <string.h>
int main()
{
int num[1501],index,min,n;
int *p2,*p3,*p5;
p2=p3=p5=&num[1];
num[1]=1;
for (index=2;index<=1500;index++)
{
if (*p2 * 2<*p3 * 3) min = *p2 * 2;
else min= *p3 * 3;
if (min> *p5 * 5) min=*p5 * 5;
num[index] = min;
if(num[index]==*p2*2) p2++;
if(num[index]==*p3*3) p3++;
if(num[index]==*p5*5) p5++;
}
while(scanf("%d",&n) && n!=0)
{
printf("%d\n",num[n]);
}
return 0;
}
本題選自北大POJ 題庫 (http://poj.org/problem?id=2545)
Description
For each three prime numbers p1, p2 and p3, let's define Hamming sequence Hi(p1, p2, p3), i=1, ... as containing in increasing order all the natural numbers whose only prime divisors are p1, p2 or p3.
For example, H(2, 3, 5) = 2, 3, 4, 5, 6, 8, 9, 10, 12, 15, 16, 18, 20, 24, 25, 27, ...
So H5(2, 3, 5)=6.
Input
In the single line of input file there are space-separated integers p1 p2 p3 i.
Output
The output file must contain the single integer - Hi(p1, p2, p3). All numbers in input and output are less than 10^18.
Sample Input
7 13 19 100
Sample Output
26590291
(1)編程思路。
弄明白了例14的編程思想,本題就簡單了,無非是將例14中的質數2,三、5參數化爲p一、p2和p3而已。
(2)源程序。
#include <stdio.h>
int main()
{
long long p1,p2,p3,H[100005];
int n,i,a1,a2,a3;
while(scanf("%lld%lld%lld%d",&p1,&p2,&p3,&n)!=EOF)
{
H[0] = 1;
a1=a2=a3=0;
for (i = 1;i<=n;i++)
{
H[i] = p1*H[a1]<p2*H[a2]?p1*H[a1]:p2*H[a2];
if (H[i]>p3*H[a3]) H[i]=p3*H[a3];
if(H[i]==p1*H[a1]) a1++;
if(H[i]==p2*H[a2]) a2++;
if(H[i]==p3*H[a3]) a3++;
}
printf("%lld\n",H[n]);
}
return 0;
}
本題選自洛谷題庫 (https://www.luogu.org/problem/ P2723)
題目描述
對於一給定的素數集合 S = {p1, p2, ..., pK},考慮一個正整數集合,該集合中任一元素的質因數所有屬於S。這個正整數集合包括,p一、p1*p二、p1*p一、p1*p2*p3...(還有其它)。該集合被稱爲S集合的「醜數集合」。注意:咱們認爲1不是一個醜數。
將醜數集合中每一個數從小到大排列,每一個醜數都是素數集合中的數的乘積,第N個「醜數」就是在能由素數集合中的數相乘得來的(包括它自己)第n小的數。
你的工做是對於輸入的集合S去尋找「醜數集合」中的第N個「醜數」。
輸入格式
第 1 行: 二個被空格分開的整數:K 和 N,1<= K<=100 ,1<= N<=100,000。
第 2 行: K 個被空格分開的整數:集合S的元素。
輸出格式
單獨的一行,輸出對於輸入的S的第N個醜數。全部輸出答案能夠用longint(32位整數)存儲。
輸入樣例
4 19
2 3 5 7
輸出樣例
27
(1)編程思路。
本題在習題14-1的基礎上更進一步,能夠指定多個質數,這些質數來自集合S。所以在習題14-1的基礎上,用數組p[101]來代替p一、p2和p3,採用循環處理便可。具體參見源程序。
(2)源程序。
#include <stdio.h>
int main()
{
int p[101],a[101],H[100005];
int k,n,i,j;
scanf("%d%d",&k,&n);
H[0] = 1;
for (i=1;i<=k;i++)
{
scanf("%d",&p[i]);
a[i]=0;
}
for (i = 1;i<=n;i++)
{
H[i] = p[1]*H[a[1]];
for (j=2;j<=k;j++)
if (H[i]>p[j]*H[a[j]]) H[i]=p[j]*H[a[j]];
for (j=1;j<=k;j++)
if(H[i]==p[j]*H[a[j]]) a[j]++;
}
printf("%d\n",H[n]);
return 0;
}
問題描述
一個集合S有以下元素:1是集合S的元素;若x是集合S的元素,則2x+1,3x+1也是集合S的元素。將集合S的元素按從小到大排列後,問第N個元素是多少?
輸入格式
輸入包含多個數據,每一個數據爲一個正整數N (1 <= N <= 10000000)。.
輸出格式
對每一個N,在單獨一行輸出集合S中第N個元素。
輸入樣例
100
254
輸出樣例
418
1461
(1)編程思路。
這道習題和例14的解題思路是徹底同樣的。兩個指針p2和p3從0開始起頭並進,一個表示 x2+1,另外一個表示x3+1,哪一個小前進哪一個,若是兩個相等就都前進。這樣就能夠產生出遞增的不重複的序列。
定義數組int num[10000001]保存產生的這個序列的前10000000項,這樣輸入n後,直接輸出數組元素num[n]便可。
(2)源程序。
#include <stdio.h>
int num[10000001];
int main()
{
int p2,p3,i,min,n;
num[1]=1;
p2=p3=1;
i=1;
while(i<10000000)
{
min=2*num[p2]+1;
if (min>3*num[p3]+1) min=3*num[p3]+1;
num[++i]=min;
if(num[i]==2*num[p2]+1) p2++;
if(num[i]==3*num[p3]+1) p3++;
}
while (scanf("%d",&n)!=EOF)
{
printf("%d\n",num[n]);
}
return 0;
}