今天學校OJ的一題判斷是質數和合數。
首先我們要弄明白質數和合數的概念:質數就是除了本身和1以外沒有其他因數的數,合數就是除了本身和1以外還有其他因數的數。注意:1既不是質數也不是合數。
明白了概念,下面在考慮題目本身。
1、輸入 :輸入待判斷的數n。(額外要求 2<=n<10000,且可連續輸入)。
2、輸出:質數:’Yes‘ ,合數:’No‘。
那么如何判斷是否為質數和合數呢?
質數就是除了本身和1以外沒有其他因數的數。
那么就只用遍歷2~n-1中的數,讓他們逐個與n取余。只要其中一個數可與n取余得0,即為可整除,即可判斷不是質數,是合數。
如下算法:(需注意的是2在判斷時需額外判斷,因為2~n-1會報錯。)
1 #include 2 int main() 3 { 4 int n; 5 while(scanf("%d",&n)!=EOF) 6 { 7 8 if (2<n<10000) 9 { 10 int flag=1; 11 for (int i=2;i<=n-1;i++) 12 { 13 if (n%i==0) 14 {flag=0; 15 break;} 16 } 17 if (flag) printf("Yes\n"); 18 else printf("No\n") ; 19 } 20 else if (n==2) printf("Yes\n"); 21 else printf("輸入錯誤\n"); 22 } 23 return 0; 24 }
以上算法的復雜度是O(n),最差的情況下運行n次。如需改進,我們可以在整除的地方思考一下,要判斷n在2~(n-1)處是否能整除,而在大於n/2時無論其取何值,都不可能使n被整除,所以只要判斷2~n/2之間的數是否能整除n即可。
代碼如下:
1 #include 2 int main() 3 { 4 int n; 5 while(scanf("%d",&n)!=EOF) 6 { 7 8 if (2<n&&n<10000) 9 { 10 int flag=1; 11 for (int i=2;i<=n/2;i++) 12 { 13 if (n%i==0) 14 {flag=0; 15 break;} 16 } 17 if (flag) printf("Yes\n"); 18 else printf("No\n") ; 19 } 20 else if (n==2) printf("Yes\n"); 21 else printf("輸入錯誤\n"); 22 } 23 return 0; 24 }
實際上我們可以證明,如果n不是素數,那么n必須有一個大於1且小於或者等於√n。證明過程:
因為n不是素數,所以會存在兩個數p和q,滿足n=pq且1<p≤q。注意到n=√n*√n。p必須小於等於√n。
所以代碼可改為如下:
1 #include<stdio.h> 2 #include<math.h> 3 4 int main() 5 { 6 int n; 7 while(scanf("%d",&n)!=EOF) 8 { 9 10 if (3<n&&n<10000) 11 { 12 int flag=1; 13 for (int i=2;i<=(int)sqrt(n);i++) 14 { 15 if (n%i==0) 16 {flag=0; 17 break;} 18 } 19 if (flag) printf("Yes\n"); 20 else printf("No\n") ; 21 } 22 else if (n==2||n==3) printf("Yes\n"); 23 else printf("輸入錯誤\n"); 24 } 25 return 0; 26 }
這就是今天get到的一個算法。
此外,通過我的思考我解決了一個我遇到的一個問題。在循環判斷語句中,根據判斷條件會進行循環判斷,如果要待循環全部進行完進行一個總的判斷,可設置一個標志變量記錄。(就比如本題,要等所有在區間內的數全部測試是否能整除,才能判斷是否為質數,這時可添加一個局部變量flag來記錄每次循環判斷的值並最終進行匯總)。
路漫漫~~~~