《編程之美》讀書筆記(十三):“找合格整數”

來源:互聯網
上載者:User

題目:任意給定一個正整數N,求一個最小的正整數M(M>1),使得N*M的十進位表示形式裡只含有1和0.
解決這個問題首先考慮對於任意的N,是否這樣的M一定存在。可以證明,M是一定存在的,而且不唯一。
簡單證明:因為

 

這是一個無窮數列,但是數列中的每一項取值範圍都在[0, N-1]之間。所以這個無窮數列中間必定存在迴圈節。即假設有s,t均是正整數,且s<t,有 。於是迴圈節長度為t-s。於是10^s = 10^t。因此有:
,所以

例如,取N=3,因為10的任何非負次方模3都為1,所以迴圈節周期為1.有:

給定N,求M的方法:
方法一:給定N,令M從2開始,枚舉M的值直到遇到一個M使得N*M的十進位表示中只有1和0.
方法二:求出10的次方序列模N的餘數序列並找出迴圈節。然後搜尋這個餘數序列,搜尋的目的就是要在這個餘數序列中找到一些數出來讓它們的和是N的倍數。例如N=13,這個序列就是1,10,9,12,3,4然後不斷迴圈。很明顯有1+12=13,而1是10的0次方,12是10的3次方,所以這個數就是1000+1=1001,M就是1001/13=77。
方法三:因為N*M的取值就是1,10,11,100,101,110,111,......所以直接在這個空間搜尋,這是對方法一的改進。搜尋這個序列直到找到一個能被N整除的數,它就是N*M,然後可計算出M。例如N=3時,搜尋樹如下:

中括弧內表示模3的餘數。括弧外表示被搜尋的數。左子樹表示0,右子樹表示1.中搜尋到第二層(根是第0層)時遇到111,它模3餘數為0.所以N*M=111, M=111/3=37。
方法四:對方法三的改進。將方法三的搜尋空間按模N餘數分類,使得搜尋時間和空間都由原來的指數級降到了O(N)。改進的原理:假設當前正在搜尋由0,1組成的K位十進位數,這樣的K位十進位數共有2^k個。假設其中有兩個數X、Y,它們模N同餘,那麼在搜尋由0、1組成的K+1位十進位數時,X和Y會被擴充出四個數:10X, 10X+1, 10Y, 10Y+1。因為X和Y同餘(同餘完全可以看作相等),所以10X與10Y同餘,10X+1與10Y+1同餘。也就是說由Y擴充出來的子樹和由X擴充產生出來的子樹產生完全相同的餘數,如果X比Y小,那麼Y肯定不是滿足要求的最小的數,所以Y這棵子樹可以被剪掉。這樣,2^K個數按照模N餘數分類,每類中只保留最小的那個數以供擴充。原來在這一層需要搜尋2^K個數,現在只需要搜尋O(N)個數。例如,當N=9時,第0層是1(1),

如所示,第2層的110,第三層的1010、1110都因為同一層有和它同餘且更小的數而被剪掉。如果按照方法三搜尋,第三層本來應該有8個結點,但現在只有4個結點。

 

方法一的原始碼:

  1. #include <stdio.h>   
  2.   
  3. int HasOnlyOneAndZero(unsigned int n) {   
  4.     while(n) {   
  5.         if(n % 10 >= 2) return 0;   
  6.         n /= 10;   
  7.     }   
  8.     return 1;   
  9. }   
  10.   
  11. int main() {   
  12.     int n, m;   
  13.     while(scanf("%d", &n) != EOF) {   
  14.         for(m = 1;;m++) {   
  15.             if(HasOnlyOneAndZero(n*m)) {   
  16.                 printf("n = %d, m = %d, n*m = %d/n", n, m, n*m);   
  17.                 break;   
  18.             }   
  19.         }   
  20.     }   
  21.     return 0;   
  22. }  

方法三的原始碼:

  1. // 解法三(1):廣度優先搜尋   
  2. #define _CRT_SECURE_NO_WARNINGS 1   
  3.   
  4. #include <cstdio>   
  5. #include <queue>   
  6. using namespace std;   
  7.   
  8. int main() {   
  9.     int N;   
  10.     while(scanf("%d", &N) != EOF) {   
  11.         queue<int> q;   
  12.         q.push(1);   
  13.         while(!q.empty()) {   
  14.             int t = q.front();   
  15.             q.pop();   
  16.             if(t % N == 0) {   
  17.                 printf("n = %d, m = %d, n*m = %d/n", N, t/N, t);   
  18.                 break;   
  19.             }   
  20.             q.push(t * 10);   
  21.             q.push(t * 10 + 1);   
  22.         }   
  23.     }   
  24.     return 0;   
  25. }  

方法四原始碼:

  1. // 解法四:將搜尋空間分過類的廣度搜尋,這樣空間佔用是O(N)而不是   
  2. // 指數級。分類的原則是按照模N的餘數分類    
  3. #define _CRT_SECURE_NO_WARNINGS 1   
  4.   
  5. #include <cstdio>   
  6. #include <bitset>   
  7. #include <vector>   
  8. #include <queue>   
  9. using namespace std;   
  10.   
  11. struct QNode {   
  12.     int v, r; // v is value, r is remainder   
  13.     QNode(int vv, int rr): v(vv), r(rr) {}   
  14.     QNode(): v(0), r(0) {}   
  15. };   
  16.   
  17. int main() {   
  18.     int N;   
  19.     while(scanf("%d", &N) != EOF) {   
  20.         //bitset<N> bn;   
  21.         queue<QNode> q;   
  22.         q.push(QNode(1, 1));   
  23.         while(!q.empty()) {   
  24.             //bn.reset();   
  25.             vector<bool> bn(N, false);   
  26.             int s = q.size();   
  27.             while(s--) {   
  28.                 QNode t = q.front();   
  29.                 if(t.r == 0) {   
  30.                     printf("n = %d, m = %d, n*m = %d/n", N, t.v/N, t.v);   
  31.                     goto ok;   
  32.                 }   
  33.                 q.pop();   
  34.                 if(!bn[t.r * 10 % N]) {   
  35.                     bn[t.r * 10 % N] = true;   
  36.                     q.push(QNode(t.v * 10, t.r * 10 % N));   
  37.                 }   
  38.                 if(!bn[(t.r * 10 + 1) % N]) {   
  39.                     bn[(t.r * 10 + 1) % N] = true;   
  40.                     q.push(QNode(t.v * 10 + 1, (t.r * 10 + 1) % N));   
  41.                 }   
  42.             }   
  43.         }   
  44. ok:;   
  45.     }   
  46.     return 0;   
  47. }  

原文連結:http://blog.csdn.net/jcwKyl/archive/2009/02/02/3859155.aspx

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.