• 数据结构与算法分析


    以下内容均节选自《算法导论》第31章

    最大公约数

    定义:若:
    [egin{array}{l}
    a = p_1^{e_1}p_2^{e_2} ldots p_r^{e_r}\
    b = p_1^{f_1}p_2^{f_1} ldots p_r^{f_r}
    end{array}]

    则:
    [gcd( a,b) = p_1^{min ( e_1,f_1)}p_2^{min ( e_2,f_2)} cdots p_r^{min ( e_r,f_r )}]

    GCD递归定理:对任意非负整数a和任意正整数b,
    [gcd (a,b) = gcd ( b,amod b )]

    证明:

    先证明充分性  

    [gcd ( a,b)|gcd ( b,amod bt)]

    如果设

    [d = gcd( a,b)]

    则   

    [d|a,d|b]

    由取模定义,可以推导出:
    [( a\,mod \,bt) = a - qb,q = lfloor {a/b} floor ]

    因为 ( a mod b) 是 a 与 b 的线性组合,所以由等式:
    [d|a& d|b Rightarrow d|( {ax + by} )]

    可知
    [d|gcd ( {a\,mod \,b} )]

    因此,因为 d | b 并且 d | ( a mod b ) ,由最大公约数定义可得:d | gcd ( b , a mod b ) ,即:
    [gcd ( a\,mod \,b )|gcd ( b,a\,mod \,b )]

    必要性证明过程与上述过程类似,故略去。

    欧几里德算法

    通过上述递归定理,我们可以求解最大公约数:

    //c++语言表示欧几里德算法
    int gcd(int a,int b){
    	if(b==0) return a;
    	else return gcd(b,a%b);
    }

    下面来举例说明该算法的运行过程。考虑 gcd (30 , 21) 的计算过程:
    [gcd ( {30,21} ) = gcd ( {21,9} ) = gcd ( 9,3) = gcd ( {3,0} ) = 3]

    在这个计算过程中,三次递归调用了欧几里德算法。

    注:

         默认假设 a>b>0。若b>a>0,则gcd(a,b)会立即调用gcd(b,a).

    即如果第一个自变量小于第二个自变量,则gcd算法进行一次递归调用使两自变量兑换,然后继续往下执行。

    类似的,如果b=a>0,则过程在进行一次调用后终止,因为 a mod b = 0

    欧几里德算法的推广形式

    我们推广该算法,使他能计算出满足下列条件的整系数x和y:
    [d = gcd ( a,bt) = ax + by]

    定理二:

           如果 a 和 b 是不都为 0 的任意整数,则gcd(a,b)是a和b的线性组合集合 { ax + by | x , y 为整数 } 中的最小正元素.

    证明

       设 s 是 a 与 b 的线性组合集中的最小正元素,并且存在x,y,使得 s = ax + by 成立。设
    [q = leftlfloor {a/s} ight floor ]

    则有 :
    [amod s = a - qs = a - q( ax + by) = a( 1 - qx) + b( - qy )]

    因此,a mod s 也是a与b的一种线性组合。但由于a mod s 取值范围 [ 0 ,s ) ,所以 a mod s=0,

    因为s是满足这样线性组合的最小正整数,故 a mod s 不能取正数只能取 0.

    因此有 s | a ,类似的可推得 s | b。

    因此 s 是a与b的公约数,所以 gcd( a , b ) >= s .

    又因为 gcd( a , b ) 能被 a 与 b 整除,并且 s = ax + by .

    所以 gcd( a , b ) | s . 

    但由gcd( a , b ) | s 和 s >0 ,可知 gcd( a , b ) <= s .

    故 gcd( a , b ) = s ,证毕

    扩展欧几里德算法:

    int extended_gcd(int a,int b,int x,int y){
    	if(b==0){
    		x=1,y=0;
    		return a;
    	}
    	int r=extended_gcd(b,a%b,x,y);
    	
    	int tmp=x;
    	x=y;
    	y=tmp-a/b*y;
    
    	return r;
    }

    过程详解:

    首先,我们需要通过下述公式获得 (d’,x’,y’)
    [d' = gcd ( b,amod b ) Rightarrow d' = bx' + ( amod b )y']

    由于:
    [d = gcd ( a,b) = d' = gcd ( b,amod b)]

    为了得到 d=ax+by 中的 x 和 y,我们改写上述等式为:
    [d = d' = bx' + (a - leftlfloor {a/b} ight floor )y' = ay' + b( x' - leftlfloor {a/b} ight floor y')]

    因此,当选择:
    [left{ egin{array}{l}
    x = y'\
    y = x' - leftlfloor {a/b} ight floor y'
    end{array} ight.]

    就可以满足等式 d = ax + by .这样就证明了extended_gcd算法的正确性。

  • 相关阅读:
    如何在某些情况下禁止提交Select下拉框中的默认值或者第一个值(默认选中的就是第一个值啦……)
    渗透测试
    如何制作chrome浏览器插件之一
    linux中的vi命令
    链栈
    二进制转16进制JAVA代码
    抽象数据类型的表示与实现
    变量的引用类型和非引用类型的区别
    说明exit()函数作用的程序
    计算1-1/x+1/x*x
  • 原文地址:https://www.cnblogs.com/ZJUT-jiangnan/p/3938402.html
Copyright © 2020-2023  润新知