poj 1061 青蛙的约会 -扩展欧几里德算法

来源:互联网 发布:mac无法删除普通用户 编辑:程序博客网 时间:2024/05/23 14:16

设过s步后两青蛙相遇,则必满足以下等式:

    (x+m*s)-(y+n*s)=k*l(k=0,1,2....)

  稍微变一下形得:

    (n-m)*s+k*l=x-y

    令n-m=a,k=b,x-y=d,即

    a*s+b*l=c

其实就是扩展欧几里德算法-求解不定方程 。 

  只要上式存在正整数解,则两青蛙能相遇,否则不能。

对原方程 a * t + b * p = d,我们要求出一组t,p;

显然c一定是gcd(a,b)的倍数,否则,两边同时除以gcd(a,b),右边会得到小数,不合法;

从而d/gcd(a,b)一定是整数;

c=gcd(a,b);

所以我们只需要通过欧几里德扩展原理求得 a * t0 + b * p0 =gcd(a,b);


得到t0,然后t0*(d/c)便是最小的解了; (因为gcd(a,b)*d/c =d)

即方程: a * t0 *(d / c) + b * p0 * (d / c) = d; 但是t0可能是负数

我们做一点变换得到

a * ( t0 *(d / c) + b*n) + b * (p0 * (d / c) – a*n) = d; (n是自然数)    (+a*b*n-a*b*n)

所以解为t=  t0*(d/c)%b   ,while( t< 0 ){  t+= b;     }


那么怎么通过欧几里德扩展原理求t0呢?
就是对于 a*x+b*t=gcd(a,b) 这样一个方程,假设a>b,有两种情况
情况1、如果b=0,方程解为x=1;y=0;
情况2、如果ab!=0,
  设 a*x+b*y=gcd(a,b);   (1)
由1,以及欧几里德原理,在求gcd时,我们知道有gcd(a,b)=gcd(b,a%b);
那么现在把(1)中的 a,b 替换成b,a%b,得到

    b * x0 + (a % b) * y0 = gcd( b, a % b);     (2)

联立两式,

a * x + b * y = b * x0 + (a % b) * y0

                     = b * x0 + (a – a / b * b) * y0               

                     = a * y0 + ( x0 – a / b * y0 ) * b

          所以得到 x = y0, y = x0 – a / b * y0;

而y0,x0就又得通过y1,x1来求得,也就是像求gcd一样,一直递归下去 ,直到最后a%b==0,

此时 的x0=1;y=0; (相当于情况1)

 以下是求扩展欧几里德的程序

void extend_euild(__int64 a, __int64 b){if (b==0){t=1;p=0;}else{extend_euild(b,a%b);__int64 tmp=t;t=p;p=tmp-a/b*p;}}


以下是ac代码: 
#include <cstdio>#include <cmath>#include <cstring>#include <string>#include <algorithm>#include <iostream>#include <queue>#include <map>#include <set>#include <vector>using namespace std; __int64 gcdc(__int64 a,__int64 b){      if(b==0)          return a;           return gcdc(b,a%b);  }  __int64 t,p,c;void extend_euild(__int64 a, __int64 b){if (b==0){t=1;p=0;}else{extend_euild(b,a%b);__int64 tmp=t;t=p;p=tmp-a/b*p;}}int main(){__int64 x,y,n,m,l;scanf("%I64d%I64d%I64d%I64d%I64d",&x,&y,&m,&n,&l);if (m==n){          cout<<"Impossible"<<endl;          return 0;      }  __int64 a=n-m;__int64 b=l;__int64 d=x-y;  __int64 gcd=gcdc(a,b); if (d%gcd){printf("Impossible\n");return 0;}          extend_euild( a, b );                t*=  d/gcd ;        while( t< 0 )        {               t+= b;         }        printf( "%I64d\n", t%b );return 0;}


0 0
原创粉丝点击