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

设过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
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值