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

题目:

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

扩展欧几里得算法详解

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

int gcd(int a,int b){
while(b!=0){
int tmp = a%b;
a = b;
b = tmp;
}
return a;
}

扩展欧几里得算法:扩展欧几里得算法不仅可以用来求最大公约数,还可以求逆元/满足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)和前一状态的关系,算法的递归实现如下:

int exgcd(int a,int b,int &x,int &y){
/*输入ax+by=gcd(a,b)的a,b,返回gcd(a,b),同时求出满足此式的解(x,y)*/
if(b==0){
x = 1;
y = 0;
return a;
}
int p = exgcd(b,a%b,x,y);
int tmp = x;
x = y;
y = tmp - a/b*y;
return p;
}
int main(){
int x,y;
int gcd = exgcd(24,18,x,y);
printf("24*%d + 18*%d = %d\n",x,y,gcd);
return 0;
}

继续.....

仅仅知道欧几里得解\(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:

/*求逆元模板*/
int exgcd(int a,int b,int &x,int &y){
if(b == 0){
x = 1;
y = 0;
return a;
}
int p =exgcd(b,a%b,x,y);
int temp = x;
x = y;
y = temp - (a/b) *y;
return p;
}
//求逆元 求a关于m的最小逆元
int cal(int a,int m){
int x,y;
int gcd = exgcd(a,m,x,y);
if(1%gcd != 0) return -1;
x *= 1/gcd;
int ans = x % m;
if(ans<=0) ans+=m; //保证正的且最小
return ans;
} /*另一个简洁版本的求逆元*/
void exgcd(int a,int b,int &x,int &y){
if(b == 0){
x = 1;
y = 0;
}else{
exgcd(b,a%b,y,x);
y = y - (a/b)*x; //此处应注意
}
}

例题:青蛙约会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 2 3 4 5

Sample Output

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\)。

实现代码:

#include<iostream>
using namespace std;
typedef long long ll;
ll x,y,m,n,L;
ll gcd(ll a,ll b){
while(b!=0){
ll tmp = a%b;
a = b;
b = tmp;
}
return a;
}
void exgcd(ll a,ll b,ll&x,ll &y){
if(b == 0){
x = 1;
y = 0;
}else{
exgcd(b,a%b,y,x);
y = y - (a/b)*x;
}
} int main(){
ll a,b,c,d,t1,t2,L2;
while(scanf("%lld%lld%lld%lld%lld",&x,&y,&m,&n,&L)!=EOF){
a = m-n;
b = y-x;
d = gcd(a,L);
if(b % d != 0){
printf("Impossible\n");
}else{
exgcd(a,L,t1,t2);
t1 = t1*b/d; //先变换到求at1+Lt2=y-x,再求最小,不能先求最小再变换,否则题意不符
t1 = t1 % L;
if(t1<0){
t1 += L;
}
printf("%lld\n",t1);
}
}
return 0;
}

【算法】欧几里得算法与青蛙约会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. TensorFlow tutorial

    代码示例来自https://github.com/aymericdamien/TensorFlow-Examples tensorflow先定义运算图,在run的时候才会进行真正的运算. run之前需 ...

  2. ASP.NET应用程序服务器集群方案

    本文采用Nginx来实现ASP.NET程序集群化. 准备环境 首先准备Nginx环境,Windows版本下载链接:http://nginx.org/en/download.html 解压后文件格式如下 ...

  3. webservice创建、部署和调用

    webservice 可以用于分布式应用程序之间的交互,和不同程序之间的交互. 下面通过一个简单的例子来创建一个webservice,用的是vs2010开发工具 首先创建一个web应用程序 接着我们添 ...

  4. 【转】JavaSE面试题目收集

    1.是否可以从一个static方法内部发出对非static方法的调用? 不可以.当一个static方法被调用时,可能还没有创建任何实例对象,如果从一个static方法中发出对非static方法的调用, ...

  5. 由于服务主机:DCOM服务进程占用过多CPU,导致系统卡死

    最近在使用电脑的时候,总是出现电脑死机,而且鼠标也是经常卡在那里不动了,开始以为是鼠标的问题,还换了个鼠标(飙泪中),这还是一个血的教训啊!!!之后打开任务管理器发现CPU占用已经达到100%,而且一 ...

  6. Django 提交 form 表单(使用sqlite3保存数据)

    优化 提交 form 表单,https://www.cnblogs.com/klvchen/p/10608143.html 创建数据库的字段,在 models.py 中添加 from django.d ...

  7. Python第十四天 序列化 pickle模块 cPickle模块 JSON模块 API的两种格式

    Python第十四天 序列化  pickle模块  cPickle模块  JSON模块  API的两种格式 目录 Pycharm使用技巧(转载) Python第一天  安装  shell  文件 Py ...

  8. EntityFramework Code-First—领域类配置之DataAnnotations

    本文出自:https://www.cnblogs.com/tang-tang/p/5510574.html 一.摘要 EF Code-First提供了一个可以用在领域类或其属性上的DataAnnota ...

  9. SQL Server数据库————模糊查询和聚合函数

    ***********模糊查询*********/ 关键字: like (!!!!字符串类型) in (,,)  匹配()内的某个具体值(括号里可以写多个值) between... and.. 在某两 ...

  10. 什么是validationQuery

    validationQuery是用来验证数据库连接的查询语句,这个查询语句必须是至少返回一条数据的SELECT语句.每种数据库都有各自的验证语句,下表中收集了几种常见数据库的validationQue ...