zoukankan      html  css  js  c++  java
  • 欧几里得算法--二进制欧几里得算法--拓展欧几里得算法

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

    教材的写法是:

    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 } 
  • 相关阅读:
    Spring Cloud Hystrix Dashboard的使用 5.1.3
    Spring Cloud Hystrix 服务容错保护 5.1
    Spring Cloud Ribbon 客户端负载均衡 4.3
    Spring Cloud 如何实现服务间的调用 4.2.3
    hadoop3.1集成yarn ha
    hadoop3.1 hdfs的api使用
    hadoop3.1 ha高可用部署
    hadoop3.1 分布式集群部署
    hadoop3.1伪分布式部署
    KVM(八)使用 libvirt 迁移 QEMU/KVM 虚机和 Nova 虚机
  • 原文地址:https://www.cnblogs.com/liugl7/p/4909584.html
Copyright © 2011-2022 走看看