欧几里得和扩展欧几里得算法

题目:

  1. poj 1061
  2. poj 2142
  3. 双六

扩展欧几里得算法详解

先说欧几里得算法:欧几里得算法辗转相除求\(gcd\)。求\(a、b\)的\(gcd\),则利用的性质是:\(gcd(a,b)=gcd(b,a\%b)\),而\(gcd(a,0)=a\),这样,辗转除下去,当第二个参数为0,第一个参数就是最大公约数。

  1. int gcd(int a,int b){
  2. while(b!=0){
  3. int tmp = a%b;
  4. a = b;
  5. b = tmp;
  6. }
  7. return a;
  8. }

扩展欧几里得算法:扩展欧几里得算法不仅可以用来求最大公约数,还可以求逆元/满足ax+by=gcd(a,b)的x和y。基于的原理是:ax+by=gcd(a,b)一定存在解(x,y)。

一个用处就是:问ax+by=1是否有解,就是看a,b是否互质,即gcd(a,b)=1。

求满足ax+by=gcd(a,b)的(x,y)的过程,就是证明ax+by=gcd(a,b)一定有解的过程。

\(ax+by=gcd(a,b)=gcd(b,a\%b)=bx_2+a\%by_2\)

又 \(a\%b=a-a/b*b\)

因此 \(ax+by =bx_2+(a-a/b*b)y_2 =ay_2+b(x_2-a/b*y2)\)

从而 \(x = y2;y=x_2-a/by_2\)

层层递归下去,最终当\(b=0\)时,返回\(gcd(a,b)=a\),此时有一组解\(x=1,y=0\),回溯,利用上式求出\(x,y\)。

从而,这就建立了要求的(x,y)和前一状态的关系,算法的递归实现如下:

  1. int exgcd(int a,int b,int &x,int &y){
  2. /*输入ax+by=gcd(a,b)的a,b,返回gcd(a,b),同时求出满足此式的解(x,y)*/
  3. if(b==0){
  4. x = 1;
  5. y = 0;
  6. return a;
  7. }
  8. int p = exgcd(b,a%b,x,y);
  9. int tmp = x;
  10. x = y;
  11. y = tmp - a/b*y;
  12. return p;
  13. }
  14. int main(){
  15. int x,y;
  16. int gcd = exgcd(24,18,x,y);
  17. printf("24*%d + 18*%d = %d\n",x,y,gcd);
  18. return 0;
  19. }

继续.....

仅仅知道欧几里得解\(ax+by=gcd(a,b)\)还不够,扩展欧几里得最好用的地方在于其求解乘法逆元。所谓逆元:若\(ax==1mod(m)\),则称\(x\)是\(a\)关于\(m\)的逆元,逆元可能有许多个,求的是其中最小的一个。

\(ax==1mod(m)\) \(=>\) \(ax+my=1\)有解,求此式的解中最小的\(x\)即可。即求出此式\(x\),\(x=x\%m\),如果\(x<0\),\(x+=m\)。

求解代码借助exgcd:

  1. /*求逆元模板*/
  2. int exgcd(int a,int b,int &x,int &y){
  3. if(b == 0){
  4. x = 1;
  5. y = 0;
  6. return a;
  7. }
  8. int p =exgcd(b,a%b,x,y);
  9. int temp = x;
  10. x = y;
  11. y = temp - (a/b) *y;
  12. return p;
  13. }
  14. //求逆元 求a关于m的最小逆元
  15. int cal(int a,int m){
  16. int x,y;
  17. int gcd = exgcd(a,m,x,y);
  18. if(1%gcd != 0) return -1;
  19. x *= 1/gcd;
  20. int ans = x % m;
  21. if(ans<=0) ans+=m; //保证正的且最小
  22. return ans;
  23. }
  24. /*另一个简洁版本的求逆元*/
  25. void exgcd(int a,int b,int &x,int &y){
  26. if(b == 0){
  27. x = 1;
  28. y = 0;
  29. }else{
  30. exgcd(b,a%b,y,x);
  31. y = y - (a/b)*x; //此处应注意
  32. }
  33. }

例题:青蛙约会poj 1061

代码解释:https://blog.csdn.net/liangdong2014/article/details/38732745

poj 1061 青蛙约会
两只青蛙在网上相识了,它们聊得很开心,于是觉得很有必要见一面。它们很高兴地发现它们住在同一条纬度线上,于是它们约定各自朝西跳,直到碰面为止。可是它们出发之前忘记了一件很重要的事情,既没有问清楚对方的特征,也没有约定见面的具体位置。不过青蛙们都是很乐观的,它们觉得只要一直朝着某个方向跳下去,总能碰到对方的。但是除非这两只青蛙在同一时间跳到同一点上,不然是永远都不可能碰面的。为了帮助这两只乐观的青蛙,你被要求写一个程序来判断这两只青蛙是否能够碰面,会在什么时候碰面。  我们把这两只青蛙分别叫做青蛙A和青蛙B,并且规定纬度线上东经0度处为原点,由东往西为正方向,单位长度1米,这样我们就得到了一条首尾相接的数轴。设青蛙A的出发点坐标是x,青蛙B的出发点坐标是y。青蛙A一次能跳m米,青蛙B一次能跳n米,两只青蛙跳一次所花费的时间相同。纬度线总长L米。现在要你求出它们跳了几次以后才会碰面。
\(Input:\) 输入只包括一行5个整数x,y,m,n,L,其中x≠y < 2000000000,0 < m、n < 2000000000,0 < L < 2100000000。
\(Output:\) 输出碰面所需要的跳跃次数,如果永远不可能碰面则输出一行"Impossible"

Sample Input

  1. 1 2 3 4 5

Sample Output

  1. 4

思路:

在一个周长是\(L\)的环上,A青蛙处于\(x\)处,每次跳\(m\),B青蛙处于\(y\)处,每次跳\(n\),跳相同的步数后,两青蛙处于同一位置。由此,设跳\(t\)步相遇,则:

\((x+m*t)\%L=(y+n*t)\%L\)

\(=>(m-n)*t\%L=(y-x)\%L\)

\(=>(m-n)*t\%L=y-x\)

若此式有解,则应有,

\(=>(m-n)*t_1+L*t_2=y-x\)有解,由exgcd知,有解的条件是

\(=>(y-x) \% gcd(m-n,L) =0\)

若有解,下面求解满足条件的最小\(t_1\),进而推出\(t\)。

由exgcd求出满足\((m-n)*t_1+L*t_2=gcd(m-n,L)\)的一组解:

exgcd(m-n,L,t1,t2);

由于\(y-x\)是\(gcd(m-n,L)\)的整数倍,则\((m-n)*t_1+L*t_2=y-x\)的一个解是:

\(=>t_1=t_1*(y-x)/gcd(m-n,L)\);

注意这样求出来的\(t_1\)可能并不是最小,因此对\(t_1\)做如下操作:

\(=>t_1=t_1\%L\)变为最小;

但\(t_1\)还可能是负值,因此,变为正的:

\(=>if_{ t_1<0}:t_1=t_1+L;\)

从而解出了\(t=t_1\)。

实现代码:

  1. #include<iostream>
  2. using namespace std;
  3. typedef long long ll;
  4. ll x,y,m,n,L;
  5. ll gcd(ll a,ll b){
  6. while(b!=0){
  7. ll tmp = a%b;
  8. a = b;
  9. b = tmp;
  10. }
  11. return a;
  12. }
  13. void exgcd(ll a,ll b,ll&x,ll &y){
  14. if(b == 0){
  15. x = 1;
  16. y = 0;
  17. }else{
  18. exgcd(b,a%b,y,x);
  19. y = y - (a/b)*x;
  20. }
  21. }
  22. int main(){
  23. ll a,b,c,d,t1,t2,L2;
  24. while(scanf("%lld%lld%lld%lld%lld",&x,&y,&m,&n,&L)!=EOF){
  25. a = m-n;
  26. b = y-x;
  27. d = gcd(a,L);
  28. if(b % d != 0){
  29. printf("Impossible\n");
  30. }else{
  31. exgcd(a,L,t1,t2);
  32. t1 = t1*b/d; //先变换到求at1+Lt2=y-x,再求最小,不能先求最小再变换,否则题意不符
  33. t1 = t1 % L;
  34. if(t1<0){
  35. t1 += L;
  36. }
  37. printf("%lld\n",t1);
  38. }
  39. }
  40. return 0;
  41. }

【算法】欧几里得算法与青蛙约会oj的更多相关文章

  1. 解题报告:poj1061 青蛙的约会 - 扩展欧几里得算法

    青蛙的约会 writer:pprp Time Limit: 1000MS Memory Limit: 10000K Total Submissions: 119716 Accepted: 25238 ...

  2. POJ 1061 青蛙的约会(拓展欧几里得算法求解模线性方程组详解)

    题目链接: BZOJ: https://www.lydsy.com/JudgeOnline/problem.php?id=1477 POJ: https://cn.vjudge.net/problem ...

  3. POJ 1061 青蛙的约会(扩展欧几里得算法)

    http://poj.org/problem?id=1061 思路: 搞懂这个扩展欧几里得算法花了不少时间,数论真的是难啊. 含义:找出一对整数,使得ax+by=gcd(a,b). 接下来看这道题目, ...

  4. 最小公约数(欧几里得算法&amp;&amp;stein算法)

    求最小公约数,最easy想到的是欧几里得算法,这个算法也是比較easy理解的,效率也是非常不错的. 也叫做辗转相除法. 对随意两个数a.b(a>b).d=gcd(a.b),假设b不为零.那么gc ...

  5. Python 最大公约数的欧几里得算法及Stein算法

    greatest common divisor(最大公约数) 1.欧几里得算法 欧几里德算法又称辗转相除法,用于计算两个正整数a,b的最大公约数. 其计算原理依赖于下面的定理: 两个整数的最大公约数等 ...

  6. RSA算法的C++string实现(模幂算法和欧几里得算法的使用)后附思路

    void resetNumA(string numAStr); //使用string重置numB void resetNumB(string numBStr); //将数组转换为字符串,用于输出 st ...

  7. 欧几里得算法/欧几里得扩展算法-python

    说在开头. 出于对欧几里得的尊重,先简单介(cou)绍(ge)一(zi)下(shu).. 欧几里得,古希腊人,数学家.他活跃于托勒密一世时期的亚历山大里亚,被称为“几何之父”. 他最著名的著作< ...

  8. python常用算法(6)——贪心算法,欧几里得算法

    1,贪心算法 贪心算法(又称贪婪算法)是指,在对问题求解时,总是做出在当前看来是最好的选择.也就是说,不从整体最优上加以考虑,他所做出的的时在某种意义上的局部最优解. 贪心算法并不保证会得到最优解,但 ...

  9. [算法]求满足要求的进制(辗转相除(欧几里得算法),求最大公约数gcd)

    题目 3在十进制下满足若各位和能被3整除,则该数能被3整除. 5在十六进制下也满足此规律. 给定数字k,求多少进制(1e18进制范围内)下能满足此规律,找出一个即可,无则输出-1. 题解 写写画画能找 ...

随机推荐

  1. C#线程安全使用(五)

     CancellationToken的多种应用 这是线程安全的最后一篇了,主要介绍CancellationToken的多种应用. 1,ThreadPool直接启动线程,传递CancellationTo ...

  2. Docker进阶之二:Docker内部组件

    Docker内部组件 一.Namespaces 命名空间,Linux内核提供的一种对进程资源隔离的机制,例如进程,网络,挂载点等资源.    docker run -d busybox ping ba ...

  3. 展开隐形的翅膀,WPR003N补完篇

    在上一回合要搞刷机!从它的尸体上踏过去!钢板云路由!WPR003N复活!成功启动OPENWRT中,笔者成功的让一个4年前主流芯片搭上OS的快船,留下一段佳话. 今天看着抽屉里的WPR003N,回忆它之 ...

  4. 使用C# 操作存储过程,执行sql语句通用类

    如何使用C# 操作存储过程,执行sql语句? 闲话不多说,直接上代码:     /// <summary>    /// Sql通用类    /// </summary>    ...

  5. eclipse建立工作集管理项目

    废话不多说,直接上图 然后新建java working set管理项目,让自己的项目清晰明了

  6. footer固定在页面底部的实现方法总结

    方法一:footer高度固定+绝对定位 HTML代码: <body> <header>头部</header> <main>中间内容</main&g ...

  7. 安卓5.0系统怎么无Root激活XPOSED框架的方法

    在大多团队的引流或业务操作中,基本上都需要使用安卓的强大Xposed框架,几天前,我们团队买来了一批新的安卓5.0系统,基本上都都是基于7.0以上系统,基本上都不能够获得Root的su权限,纵然一些能 ...

  8. <自动化测试方案_7>第七章、PC端UI自动化测试

    第七章.PC端UI自动化测试 UI自动化测试又分为:Web自动化测试,App自动化测试.微信小程序.微信公众号UI层的自动化测试工具非常多,比较主流的是UFT(QTP),Robot Framework ...

  9. 【English】十三、英语中的连词有哪些,都有什么作用

    一.什么是连词 参考:https://m.hujiang.com/en_cixing/yylc/ 连词是一种虚词,用于连接单词.短语.从句或句子,在句子中不单独用作句子成分. 连词按其性质可分为并列连 ...

  10. SQL SERVER 2012 AlwaysOn– 数据库层面 02

    搭建 AlwaysOn 是件非常繁琐的工作,需要从两方面考虑,操作系统层面和数据库层面,AlwaysOn 非常依赖于操作系统,域控,群集,节点等概念: DBA 不但要熟悉数据库也要熟悉操作系统的一些概 ...