• 欧几里得算法--二进制欧几里得算法--拓展欧几里得算法


    首先说一下,欧几里得算法:求两个数的最大公约数

    教材的写法是:

    1 //输入要求a>=b>=0 
    2 unsigned euclid(unsigned a,unsigned b){
    3     if(b==0) return a;  
    4     return euclid(b,a%b);
    5 }

    当然也可以改成非递归的迭代版本:

     1 int Gcd(int a, int b)
     2 {
     3     while(b != 0)
     4     {
     5       int r = b;
     6       b = a % b;
     7       a = r;
     8     }
     9     return a;
    10 }

    上个世纪60年代研究人员对这个古老的算法进行了改进,称为二进制欧几里得算法:

    基于的原理是:

    1. 若 N 和 M 是偶数,gcd(N, M) = 2 gcd(N/2, M/2) ,
    2. 若 N 是偶数而 M 是奇数,那么 gcd(N, M) = gcd(N/2, M) ,
    3. 若 N 和 M 都是奇数,那么 (由于 N-M 是偶数) |N-M| < max(N,M) 。用 |N-M| 替换两者中的较大者   

      该算法称为 二进制 因为,与原来的不同,它不使用通常的除法而只使用除以2的。由于计算机数字总是用二进制系统表示,你不会对有一种特殊的 机器指令 以高效的方式实现 除以 2而感到惊讶。这称为 右移位,其中最右一位被舍弃,其他的位向右移动一位,而最左一位被设为0。

      另一个顺手拈来的操作是按位与 & 。对任意整数 N 来说,N & 1 是 1 或 0 。当且仅当 N 是奇数时它为 1 。按位与也在硬件中实现,例如,作为 机器指令 

    递归版本:

     1 unsigned int gcd(unsigned int u, unsigned int v)
     2 {
     3     // simple cases (termination)
     4     if (u == v) return u;
     5     if (u == 0) return v;
     6     if (v == 0) return u;
     7 
     8     // look for factors of 2
     9     if (~u & 1) // u is even
    10     {
    11         if (v & 1)  return gcd(u >> 1, v);             // u is even,v is odd
    12         else        return gcd(u >> 1, v >> 1) << 1;   // both u and v are even
    13             
    14     }
    15     if (~v & 1)    return gcd(u, v >> 1);              // u is odd, v is even
    16     
    17     
    18     // both u and v are odd,reduce larger argument
    19     if (u > v)     return gcd((u - v) >> 1, v);
    20 
    21     return gcd((v - u) >> 1, u);
    22 }
    递归—二进制欧几里得算法

    当然也可以改成迭代版本:

     1 unsigned int gcd2(unsigned int u, unsigned int v)
     2 {
     3   int shift;
     4 
     5   /* GCD(0,v) == v; GCD(u,0) == u, GCD(0,0) == 0 */
     6   if (u == 0) return v;
     7   if (v == 0) return u;
     8  
     9   /* Let shift := lg K, where K is the greatest power of 2
    10         dividing both u and v. */
    11   for (shift = 0; ((u | v) & 1) == 0; ++shift) {
    12          u >>= 1;
    13          v >>= 1;
    14   }
    15  
    16   while ((u & 1) == 0)
    17     u >>= 1;
    18  
    19   /* From here on, u is always odd. */
    20   do {
    21        /* remove all factors of 2 in v -- they are not common */
    22        /*   note: v is not zero, so while will terminate */
    23        while ((v & 1) == 0)  /* Loop X */
    24            v >>= 1;
    25 
    26        /* Now u and v are both odd. Swap if necessary so u <= v,
    27           then set v = v - u (which is even). For bignums, the
    28           swapping is just pointer movement, and the subtraction
    29           can be done in-place. */
    30        if (u > v) {
    31          unsigned int t = v; v = u; u = t;}  // Swap u and v.
    32        v = v - u;                       // Here v >= u.
    33      } while (v != 0);
    34 
    35   /* restore common factors of 2 */
    36   return u << shift;
    37 }
    迭代—二进制欧几里得算法

    拓展欧几里得的算法是:

            欧几里得定理告诉我们,只要能找到整数x和y,使得ax+by=d,则d就是a和b的最大公因子。而且如果d是a和b的最大公因子,则d一定可以表示为ax+by的形式。    

            运用下列函数的前提是gcd(a,b)=d,即d是a和b的最大公约数,则该函数可以计算得到ax+by=d中的x值。

     1 //要求是gcd(a,b)=d      
     2 int e_gcd(int a,int b,int &x,int &y){
     3     if(b==0){
     4         x=1;
     5         y=0;
     6         return a;
     7     }
     8     int ans=e_gcd(b,a%b,x,y);
     9     int temp=x;
    10     x=y;
    11     y=temp-a/b*y;
    12     return ans;
    13 } 

    拓展欧几里得算法的一个运用是计算模n逆元:如果有ax=1(mod N),那么我们称x是a的模N逆元。

     1 //计算得到 “a模m逆元” 
     2 int cal(int a,int m){   
     3     int x,y;
     4     int gcd=e_gcd(a,m,x,y);
     5     if(1%gcd!=0)  return -1;
     6     x*=1/gcd;
     7     m=abs(m);
     8     int ans=x%m;
     9     if(ans<=0) ans+=m;
    10     return ans;
    11 }

    其实,“a的模N逆元”,主要在RSA中计算解密密钥时用的较多。关于RSA的细节,这里不赘述,详情参加另外一篇博客。在计算RSA中加密时,需要用到快速幂取模算法,详见九月份的一篇博客。

    贴一个应用:

    ural  Idempotents

    Time Limit:1000MS     Memory Limit:65536KB     64bit IO Format:%I64d & %I64u

    Description

    The number x is called an idempotent modulo n if
    xx = x (mod n)
    Write the program to find all idempotents modulo n, where n is a product of two distinct primes p and q.

    Input

    First line contains the number k of test cases to consider (1 ≤ k ≤ 1000). Each of the following k lines contains one number n < 10 9.

    Output

    Write on the i-th line all idempotents of i-th test case in increasing order. Only nonnegative solutions bounded by n should be printed.

    Sample Input

    inputoutput
    3
    6
    15
    910186311
    0 1 3 4
    0 1 6 10
    0 1 303395437 606790875

    AC代码:

     1 #include <iostream>
     2 using namespace std;
     3 
     4 
     5 int getp(int n){   //得到大于1的最小的因数 
     6     int p=2;
     7     while(n%p!=0){
     8         p++;
     9     }
    10     return p;
    11 }
    12 
    13 void e_gcd(int a,int b,int &x,int &y){
    14     if(b==0){
    15         x=1;
    16         y=0;
    17         return ;
    18     }
    19     e_gcd(b,a%b,x,y);
    20     int temp=x;
    21     x=y;
    22     y=temp-a/b*y;
    23     return ;
    24 } 
    25 
    26 int main()
    27 {
    28     int k;
    29     cin>>k;
    30     while(k--)
    31     {
    32         int n;
    33         cin>>n;
    34         int p=getp(n),q=n/p;
    35         int x,y;
    36         e_gcd(p,q,x,y) ;
    37         int x1=x*p;
    38         if(x1<0) x1+=n;
    39         
    40         e_gcd(q,p,x,y) ; 
    41         int x2=x*q;
    42         if(x2<0) x2+=n;
    43         if(x2<x1){
    44             int temp=x2;
    45             x2=x1;
    46             x1=temp;
    47         }
    48         cout<<0<<" "<<1<<" "<<x1<<" "<<x2<<endl;
    49     } 
    50     
    51 } 
  • 相关阅读:
    BZOJ 3631 链剖+差分
    BZOJ 1103 DFS序+线段树
    BZOJ 3629 约数和定理+搜索
    198. House Robber
    152. Maximum Product Subarray
    139. Word Break
    132. Palindrome Partitioning II
    120. Triangle
    115. Distinct Subsequences
    97. Interleaving String
  • 原文地址:https://www.cnblogs.com/liugl7/p/4909584.html
Copyright © 2020-2023  润新知