POJ 1061 青蛙的约会

题目大意:中文

题目链接

注释代码:

//引入概念——求解线性不定方程
//求解线性不定方程ax + by = c
//求a、b的最大公约数(Greatest Common Divisor,简称GCD)即d = gcd(a, b),算法为辗转相除法(即欧几里得算法)
//若d能整除c(即c mod d = 0)则表示方程有解,否则误解
//若有解则利用扩展欧几里得算法求解方程的根,步骤为:
  //先将方程两边同除以d得到 _ax + _by = _c
  //求出该方程的唯一解xx和yy
  //最后得到整个线性方程的全解(即解集)
  //x = _c * xx + t * _b
  //y = _c * yy - t * _a
  //t为任意整数

/*                           
 * Problem ID : POJ 1061 青蛙的约会
 * Author     : Lirx.t.Una                           
 * Language   : C++               
 * Run Time   : 0 ms                           
 * Run Memory : 172 KB                           
*/

#include <stdio.h>

typedef	long long	llg;

llg
gcd( llg a, llg b ) {//辗转相除法
	
	if ( !b )
		return a;

	//递归算法
	//return gcd( b, a % b );
	
	llg		t;
	
	//非递归算法
	while ( b )	{
		
		t = b;
		b = a % b;
		a = t;
	}
	
	return a;
}

void
xuclid( llg a, llg b, llg &x, llg &y ) {//extend Euclid
	//扩展欧几里得算法
	
	if ( !b ) {
		
		x = 1;
		y = 0;
		
		return ;
	}
	
	llg		t;
	
	xuclid( b, a % b, x, y );//得到bx + ( a % b )y = c的解
	
	//计算公式
	t = x;
	x = y;
	y = t - a / b * y;
}

int
main() {
	
	llg		x, y, m, n, l;//两青蛙的起始位置、速度、维度线长
	llg		a, b, c;//方程系数
	llg		s, k;//step,步数,绕维度线的圈数
	llg		d;//最大公约数
	llg		t;//temporary,临时变量
	
	scanf("%lld%lld%lld%lld%lld", &x, &y, &m, &n, &l);

	//待解的线性不定方程为:
	//(x + m * s) - (y + n * s) = k * l (k为整数)
	//化简后得:
	//(n - m) * s + k * l = x - y
	//令
	a = n - m;
	b = l;
	c = x - y;
	//之后按照公式计算解即可
	
	d = gcd( a, b );
	
	if ( c % d ) {
		
		puts("Impossible");
		return 0;
	}
	
	a /= d;
	b /= d;
	c /= d;
	
	xuclid( a, b, s, k );

	//由于解必须是正整数,且为最小值,因此需要对解进行修正	
	t = c * s / b;//使t * b和c * s最接近
	s = c * s - t * b;
	
	//由于b = l必定大于0,因此可以直接相加,不必考虑b小于0的情况
	if ( s < 0 )
		s += b;
	
	printf("%lld\n", s);
	
	return 0;
}

无注释代码:

#include <stdio.h>

typedef	long long	llg;

llg
gcd( llg a, llg b ) {
	
	if ( !b )
		return a;
	
	llg		t;
	
	while ( b )	{
		
		t = b;
		b = a % b;
		a = t;
	}
	
	return a;
}

void
xuclid( llg a, llg b, llg &x, llg &y ) {
	
	if ( !b ) {
		
		x = 1;
		y = 0;
		
		return ;
	}
	
	llg		t;
	
	xuclid( b, a % b, x, y );
	
	t = x;
	x = y;
	y = t - a / b * y;
}

int
main() {
	
	llg		x, y, m, n, l;
	llg		a, b, c;
	llg		s, k;
	llg		d;
	llg		t;
	
	scanf("%lld%lld%lld%lld%lld", &x, &y, &m, &n, &l);
	
	a = n - m;
	b = l;
	c = x - y;
	
	d = gcd( a, b );
	
	if ( c % d ) {
		
		puts("Impossible");
		return 0;
	}
	
	a /= d;
	b /= d;
	c /= d;
	
	xuclid( a, b, s, k );
	
	t = c * s / b;
	s = c * s - t * b;
	
	if ( s < 0 )
		s += b;
	
	printf("%lld\n", s);
	
	return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值