以POJ1061青蛙的约会为例谈扩展欧几里得算法
来源:互联网 发布:dede上传网站源码 编辑:程序博客网 时间:2024/05/01 20:34
青蛙的约会
Time Limit: 1000MS Memory Limit: 10000K
Total Submissions: 100498 Accepted: 19304
Description
两 只青蛙在网上相识了,它们聊得很开心,于是觉得很有必要见一面。它们很高兴地发现它们住在同一条纬度线上,于是它们约定各自朝西跳,直到碰面为止。可是它 们出发之前忘记了一件很重要的事情,既没有问清楚对方的特征,也没有约定见面的具体位置。不过青蛙们都是很乐观的,它们觉得只要一直朝着某个方向跳下去, 总能碰到对方的。但是除非这两只青蛙在同一时间跳到同一点上,不然是永远都不可能碰面的。为了帮助这两只乐观的青蛙,你被要求写一个程序来判断这两只青蛙 是否能够碰面,会在什么时候碰面。
我们把这两只青蛙分别叫做青蛙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
Source
浙江
欧几里得算法可以求出a,b的最大公约数。gcd(a,b)=gcd(b,a%b),公式两边b都靠近等号一侧,因此很好记。
int gcd(int a,int b){return 0==b?a:gcd(b,a%b);}
为什么欧几里得算法是对的,记住一个式子:a=bq+r(假设a>b。若a小于b,gcd(a,b)=gcd(b,a)。因此a大于还是小于b无所谓)。因为a%m==0且b%m==0,所以必有r%m==0:a和b的约数必是r(即a%b)的约数。同时若r%n==0,b%n==0,必有a%n==0,因此b和r的约数必是a的约数。因此a、b约数中最大值必是b、r约数中的最大值。
**
扩展欧几里得算法exGcd(a,b,x,y):求a,b的最大公约数同时可以求得方程组ax+by=gcd的一组特殊解(x,y)。
**从式子ax+by=gcd可以看出必须先求出gcd,才能求出解。而递归中的却如此。
1、假设已经找到gcd,那么y=0,x=gcd,显然是该方程的解。而且在每一层递归函数exGcd(a,b,x,y)里都有一个解(x,y)。
2、在递归回溯过程中,假设在第n+1层exGcd(a(n+1),b(n+1),x,y)找到了(x0,y0)是方程的解。那么有a(n+1)*x0+b(n+1)*y0=c(1式)。
3、根据递归过程,在第n层调用了exGcd(bn,an%bn,x,y)进入第n+1层。因此在第n+1层的解满足a(n+1)=bn,b(n+1)=an%bn,即(1)式等价于:bn*x0+(an%bn)%y0=c(2式)。又因为an%bn=an-bn*(an/bn)。所以(2式子)等价于bn*x0+(an-bn*(an/bn))*y0=bn(x0-(an/bn)*y0)+an*y0=c(3式)。
3、假设回溯到第n层时,解为(x1,y1),an*x1+bn*y1=c(4式)。对比(3式)和(4式)发现x1=y0,y1=x0-y0*(an/bn)。所以第n层的解可以通过第n+1层的解递推出来。在最深层有解x=gcd,y=0,因此层层回溯,每层都会有一个关于当前层exGcd(an,bn,x,y)的解(xn,yn)使得an*xn+bn*yn=gcd(an,bn)。因此回溯到第一层时就得到了关于第一层的解。
代码如下:
long long exGcd(long long a, long long b, long long &x, long long &y){ if(b==0){ x=1; y=0; return a; } long long g=exGcd(b,a%b,x,y); long long temp=x; x=y; y=temp-(a/b)*y;//注意此处不能写成y*a/b! return g;}
扩展欧几里得算法应用之一就是:求二元一次方程组的解(x,y), a*x+b*y=c。
注意,这里右边是c,不是gcd(a,b)。假设其中x是我们关心的,所以研究x的解的情况。计算步骤:
1、用扩展欧几里得算法求解方程:a*x+b*y=gcd(a,b). 可以同时得到gcd以及 一组特解(x0,y0)
2、如果c%gcd!=0,那么根据式子a*x+b*y=c可知其无整数解(因为a,b都可以提一个公因数gcd,但是c不能提因子gcd,等号左右两边不等价)。
3、那么a*x+b*y=c的x的特殊解x1等于a*x+b*y=gcd(a,b)的特殊解x0乘以c/gcd: x1=x0*c/gcd。4、这一步的构造很关键,因为引入了整数t,t不同解不同,这就是为什么会有无数解。因为x1*a+y1*b=x1*a+y1*b+(t*a*b/gcd-t*a*b/gcd)=a(x1+t*b/gcd)+b(y1-t*a/gcd)=c,所以方程a*x+b*y=c的x的通解就是x=x1+t*b/gcd=x0*c/gcd+t*b/gcd。
5、x有无数种情况,我们关心特殊情况,比如在实际问题中经常需要找大于0且最小的x的值。如何寻找?找x即找t,下面对t进行分析。 x=x0*c/gcd+t*b/gcd。这里的x肯定大于0,减去t*b/gcd剩下的x0*c/gcd也大于0,所以直接对x=x0*c/gcd进行分析。不妨让t=x/(b/gcd)得到x中有t个b/gcd,然后在x中减去这t个b/gcd:t=x/(b/gcd),x=x-t*(b/gcd)。此时得到的x可能小于等于0,因此要做判断,x小于等于0时加上b/gcd即可。
首先,此题有两个变量,跳的次数P和跳的圈数Q。需要求次数的最小值。当然联想到拓展欧几里得算法的应用:求解二元一次线性方程组。两只青蛙相遇的条件是:(x+mP) mod L =(y+nP) mod L=0,但是这样写不是方程式的形式,所以改成等价的方程的形式: (x+mP)-(y+nP) =Q L,等价于x-y+P(m-n)=QL,x-y=(n-m)P+QL。令c=x-y,a=n-m,b=L,则aP+bQ=c,这就是标准的二元一次方程组,两个未知量求其中一个未知量(跳到次数P)的最小值。
#include <iostream>#include <cstring>#include<cstdio>#include <algorithm>using namespace std;long long exGcd(long long a,long long b,long long &x,long long &y){ if(b==0){ x=1; y=0; return a; } long long d=exGcd(b,a%b,x,y); long long tmpX=x; x=y; y=tmpX-y*(a/b);//不能写成y*a/b return d;}int main(){ freopen("input.txt","r",stdin); freopen("output.txt","w",stdout); long long ansX,x,y,n,m,L,x0,y0,a,b,c,gcd; while(scanf("%lld%lld%lld%lld%lld",&x,&y,&m,&n,&L)==5){ c=x-y; a=n-m; b=L; gcd=exGcd(a,b,x0,y0); if(c%gcd!=0) cout<<"Impossible"<<endl; else{ ansX=x0*(c/gcd); long long t=ansX/(b/gcd); ansX=ansX-t*(b/gcd); if(ansX<0) ansX+=b/gcd; cout<<ansX<<endl; } } return 0;}
欢迎留言,积极讨论,一起进步!
- 以POJ1061青蛙的约会为例谈扩展欧几里得算法
- POJ1061 青蛙的约会(数论 扩展欧几里得算法)
- 扩展欧几里得 poj1061 青蛙的约会
- 扩展欧几里得 POJ1061青蛙的约会
- poj1061青蛙的约会(扩展欧几里得)
- poj1061青蛙的约会--扩展欧几里得
- POJ1061 青蛙的约会 扩展欧几里得
- poj1061 青蛙的约会 扩展欧几里得
- poj1061 青蛙的约会 扩展欧几里得
- poj1061青蛙的约会 扩展欧几里得
- poj1061 青蛙的约会(扩展欧几里得)
- poj1061—青蛙的约会 (扩展欧几里得)
- POJ1061青蛙的约会(扩展欧几里得)
- POJ1061 青蛙的约会(扩展欧几里得)
- poj1061青蛙的约会(扩展欧几里得)
- POJ1061 青蛙的约会(扩展欧几里得)
- POJ1061:青蛙的约会(扩展欧几里得)
- [poj1061]: 青蛙的约会(扩展欧几里得)
- LibGDX_2.1: LibGDX 应用框架(6 大系统交互接口)
- ====手势的使用
- 《疯狂JAVA讲义》——instanceof运算符
- [读书笔记] The.Way.To.Go
- c#调用JAVA提供的WebService处理日期格式
- 以POJ1061青蛙的约会为例谈扩展欧几里得算法
- iOS工程适配64-bit经验分享
- C-045.结构体指针
- 仿微信二维码的制作
- linux utils
- Android: 属性服务
- Python爬虫入门三之Urllib库的基本使用
- 查找——线性表顺序查找算法
- GPU 编程入门到精通(二)之 运行第一个程序