250 likes | 368 Views
2010 ACM. 質數. 問題. 基本: 如何判斷一個數是不是質數? 如何尋找質數? 應用: 如何對一個整數作質因數分解? 如何對一個階乘作質因數分解?. 質數的定義 ( 復習 ). 一個大於 1 的整數 p , 如果只有 1 和 p 兩個正因數, 則 p 是 質數 。 A positive integer p greater than 1 is called prime if the only positive factors of p are 1 and p . ( 取自離散課本 ). 基本一. 如何判斷一個數是不是質數?.
E N D
2010 ACM 質數
問題 • 基本: • 如何判斷一個數是不是質數? • 如何尋找質數? • 應用: • 如何對一個整數作質因數分解? • 如何對一個階乘作質因數分解?
質數的定義(復習) • 一個大於 1 的整數 p ,如果只有 1 和 p 兩個正因數,則 p 是質數。 • A positive integer p greater than 1 is called prime if the only positive factors of p are 1 and p.(取自離散課本)
基本一 如何判斷一個數是不是質數?
判別質數 • 設要拿來判斷的數為 N: • 若 2 ~ (N-1) 中的數都沒辦法整除 N,則 N 是質數。 • 若 2 ~ √N中的數都沒辦法整除 N,則 N 是質數。 • 若 2 ~ √N中的奇數都沒辦法整除 N,則 N 是質數。 • 若 2 ~ √N中的質數都沒辦法整除 N,則 N 是質數。(僅限於已經有√N以內的質數表可查的情況) 以 97(質數)為例子…
程式實作 int isprime_1(int check){ if(check == 2)return 1; // 2 is prime int count; for(count = 2; count < check; count++){ if( !(check % count) )return 0; // isn't prime } return 1; // is prime }// end of isprime_1 int isprime_2(int check){ if(check == 2)return 1; // 2 is prime int count; int bound = sqrt(check); for(count = 2; count <= bound; count++){ if( !(check % count) )return 0; // isn't prime } return 1; // is prime }// end of isprime_2 int isprime_3(int check){ int count; int bound = sqrt(check); if( !(check % 2) ){ if(check != 2)return 0; // isn't prime else return 1; // 2 is prime } for(count = 3; count <= bound; count += 2){ if( !(check % count) )return 0; // isn't prime } return 1; // is prime }// end of isprime_3
前面三種檢查範圍的比較 Demo !!(速度比較)
基本二 如何尋找質數?
尋找質數 • 要決定「N 不是質數」和「N 是質數」哪個做起來比較簡單? • 「N 不是質數」2 ~ √N中的數只要任一個能整除 N即可 • 「N 是質數」2 ~ √N中的數都不能整除 N才行 • 篩法 (Sieve of Eratosthenes) • 跳二跳四法
篩法 • 刪去不是質數的數,剩下的就是質數。 • 不是質數的數:1、質數的倍數 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
篩法 程式實作 int isprime[1000] = {0}; // prime table(bool or int) isprime[0] = isprime[1] = 1; // 0, 1 are not prime int prime = 2; // filtering while(prime < 1000){ int mul = prime * 2; while(mul < 1000){ isprime[mul] = 1; // prime's multiples mul += prime; } // move to next prime do{ prime++; }while(prime < 1000 && isprime[prime] == 1); }// end of filtering
跳二跳四法 • 把數字做分類,減少檢查範圍。 2的倍數 可能是質數 2的倍數 3的倍數 可能是質數 6的倍數 6n+1 6n+2 6n+3 6n+4 6n+5 6n+6 +2 1 2 3 4 5 6 +4 +2 7 8 9 10 11 12 +4 +2 13 14 15 16 17 18 +4 +2 19 20 21 22 23 24 +4 +2 25 26 27 28 29 30 +4 +2 31 32 33 34 35 36 +4 37 38 39 40 41 42
基本篇 整理 • 判斷質數 • 2 ~ (N-1) • 2 ~ √N • 2 ~ √N 的奇數 • 2 ~ √N 的質數 • 尋找質數 • 篩法 • 刪除「不是質數」的數 • 跳二跳四法 • 6n+1、6n+5
應用一 如何對一個整數作質因數分解?
整數的質因數分解 • 依照質數大小,從 2 開始試除 • 若可以整除,則該質數次方項加 1 • 重複除到不能整除時,換下一個質數 • 重複以上步驟,直到商為 1 為止或是超過建好的質數表範圍(sqrt(N))
質數表要多大? • 原則上建到根號 N 就好,但有的質因數會超過這個範圍,就要特別處理。 • 例子:3414 = 2 * 3 * 569但是 569 > sqrt(3414) = 58.43而且 569 是質數
應用二 如何對一個階乘作質因數分解?
階乘的質因數分解 • 直接乘開,再使用剛才教過的方法? • 乘開很麻煩,而且之後的計算量超大 • 若數字太大,會造成 overflow • 13! 大小約 1010,而 32bits 的記憶體卻只能放約 109的內容 • 21! 大小約 1020, 而 64bits 的記憶體卻只能放約 1019的內容 • 那麼 100! 呢?你還要乘開嗎? • 既然已經表示為連乘積了,那就直接拆開吧!
流程和原理 • 以 10! 為例: • 10/2 = 505/2 = 202/2 = 1 • 10/3 = 303/3 = 1 • 10/5 = 2 • 10/7 = 1 • 10! = 2^8 * 3^4 * 5^2 * 7
重點整理 • 判別質數 • 試除 • 2 ~ (N-1) • 2 ~ √N • 2 ~ √N 的奇數 • 尋找質數 • 篩法 • 剔除「不是質數」 • 跳二跳四法 • 6n+1、6n+5 • 整數的質因數分解 • 從 2 開始除 • 次方加一 • 不能整除換下一個 • 商為 1 結束 • 階乘的質因數分解 • 從 2 開始除 • 次方加上商 • 餘數太小換下一個 • 質數大於 N 結束