Change Dir

          先知cd——熱愛生活是一切藝術的開始

          統計

          留言簿(18)

          積分與排名

          “?!眰兊牟┛?/h3>

          各個公司技術

          我的鏈接

          淘寶技術

          閱讀排行榜

          評論排行榜

          復習中國剩余定理

          前幾天女朋友問我一個題目:一次酒店宴席安排賓客就座吃飯,5人一桌剩4人,7人一桌剩6人,9人一桌剩8人,11人一桌正好。問宴席共有多少人?

          一眼看去:中國剩余定理,但是答案和過程的獲取的那個揪心啊,讓我意識到,當初看過的數論的東西都忘掉了,像這些有可能在密碼學中用到的算法知識,看密碼學和算導的時候都記得很清楚,也拿實際題目演練過,但是時間一長還是忘記了?,F在把功課補一補,寫篇文章紀念一下~~~

          中國剩余定理:設n=n1*n2*...*nk,其中因子ni兩兩互質??紤]如下對應關系 a <-> (a1,a2,...,ak)其中 ai = a mod ni
          如果a<->(a1,a2,...,ak),b<->(b1,b2,...,bk)
          那么(a+b) mod n <-> ((a1+b1) mod n1, ..., (ak+bk) mod nk)
          (a-b) mod n <-> ((a1-b1) mod n1, ... , (ak-bk) mod nk)
          (ab) mod n <-> (a1b1 mod n1, ... , akbk mod nk)

          這個定理有兩個重要推論:
          (1)如果n1, n2, ... , nk兩兩互質,n=n1*n2*...*nk,則對任意整數a1, a2, ... , ak,方程組 x=ai (mod ni) 關于未知量x對模n有唯一解。
          (2)如果n1, n2, ... , nk兩兩互質,n=n1*n2*...*nk,則對所有整數x和a,x=a (mod ni) 當且僅當 x=a (mod n)。

          針對這個問題,這個定理怎么用呢?
          n1=5,n2=7,n3=9,n4=11。 n=n1*n2*n3*n4 = 3465。我們現在要求的就是a,那么與a的對應關系a1,a2,a3,a4是什么呢?
          利用公式:a1 = a mod n1 = 4,a2 = a mod n2 = 6,a3 = a mod n3 = 8,a4 = a mod n4 = 0。
          如此,n序列和a序列已經都初始化了。n也計算出來了。問題就轉化為知道這些輸入,如何能計算出a來。
          首先確定m序列,mi是什么呢?定義mi=n/ni。這是一個中間步驟,目的是為了定義c序列ci = mi * (mi-1 mod ni)。
          因為mi和ni互質,mi-1 mod ni存在。最后計算a 的方法即 a = (a1*c1 + a2*c2 + ... + ak*ck) (mod n)。

          具體細節不再多寫了,抄書的工作沒有意義。有興趣的朋友們建議多翻書吧。定理書上都有,就針對這一問題,解決方法上代碼。

          算法實現如下:
           1/**
           2 * 
           3 */

           4package algorithm.math;
           5
           6/**
           7 * @author Jia Yu
           8 * @date   2010-11-11
           9 */

          10public class ChinaModule {
          11
          12    /**
          13     * Return the greatest common divisor.
          14     */

          15    public static long gcd( long a, long b )
          16    {
          17        if( b == 0 )
          18            return a;
          19        else
          20            return gcd( b, a % b );
          21    }

          22
          23      // Internal variables for fullGcd
          24    private static long x;
          25    private static long y;
          26
          27    /**
          28     * Works back through Euclid's algorithm to find
          29     * x and y such that if gcd(a,b) = 1,
          30     * ax + by = 1.
          31     */

          32    private static void fullGcd( long a, long b )
          33    {
          34        long x1, y1;
          35
          36        if( b == 0 )
          37        {
          38            x = 1;
          39            y = 0;
          40        }

          41        else
          42        {
          43            fullGcd( b, a % b );
          44            x1 = x; y1 = y;
          45            x = y1;
          46            y = x1 - ( a / b ) * y1;
          47        }

          48    }

          49
          50    /**
          51     * Solve ax == 1 (mod n), assuming gcd( a, n ) = 1.
          52     * @return x.
          53     */

          54    public static long inverse( long a, long n )
          55    {
          56        fullGcd( a, n );
          57        return x > 0 ? x : x + n;
          58    }

          59
          60    public static long china(long[] n, long[] a) {
          61        // TODO Auto-generated method stub
          62        long n_total = 1L;
          63        final int len = n.length;
          64        for(int i=0;i<len;i++){
          65            n_total *= n[i];
          66        }

          67        
          68        long []m = new long[len];
          69        for(int i=0;i<len;i++){
          70            m[i] = n_total / n[i];
          71        }

          72        
          73        long []c = new long[len];
          74        for(int i=0;i<len;i++){
          75            c[i] = m[i] * inverse(m[i],n[i]);
          76        }

          77        
          78        long a_total = 0L;
          79        for(int i=0;i<len;i++){
          80            a_total += (a[i]*c[i]) % n_total;
          81        }

          82        a_total %= n_total;
          83        return a_total;
          84    }

          85
          86       
          87    /**
          88     * @param args
          89     */

          90    public static void main(String[] args) {
          91        // TODO Auto-generated method stub
          92        long n[] = {5,7,9,11};
          93        long a[] = {4,6,8,0};
          94        //long n[] = {3,5,7};
          95        //long a[] = {2,3,2};
          96        System.out.println(china(n,a));
          97    }

          98}

          99


          其中的GCD方法是歐幾里得求最大公約數算法,fullgcd是擴展歐幾里得算法,inverse是利用擴展歐幾里得方法求乘法逆元的方法,china是通過輸入數組求目標數的方法。
          最后得到結果2519。即總共2519名賓客。

          當時沒算出來,過了一會女朋友來短信:“我用excel做出來了”~~~~我狂汗!

          posted on 2010-11-18 10:10 changedi 閱讀(2672) 評論(1)  編輯  收藏 所屬分類: 算法

          評論

          # re: 復習中國剩余定理[未登錄] 2010-11-18 13:30 abc

          效率雖然低些,可也能算出來。
          for (int i=11;i<9999;i=i+11){

          if(i%5==4 && i%7==6 && i%9==8){
          System.out.println("The number is :" + i);
          break;
          }

          }
          The number is :2519
          The number is :5984
          The number is :9449
            回復  更多評論   

          主站蜘蛛池模板: 镶黄旗| 灌南县| 资中县| 丹寨县| 增城市| 三穗县| 静宁县| 贵州省| 和田市| 酒泉市| 三门峡市| 双峰县| 友谊县| 小金县| 方山县| 绥江县| 汾西县| 自治县| 霸州市| 甘肃省| 满洲里市| 左权县| 宜黄县| 汨罗市| 清水县| 富裕县| 全南县| 潮安县| 阳朔县| 宁明县| 广汉市| 桃源县| 上高县| 嫩江县| 永嘉县| 深泽县| 宕昌县| 梅州市| 民权县| 南宫市| 石屏县|