One Person Game ZOJ - 3593(扩展欧几里得)

One Person Game

题目链接:ZOJ - 3593
题意:在一维地图上, 有A,B,两点, 每步只能能走a或b或a+b个单位;问最少走几步能由A到B, 若不能由A走到B输出-1;
设走x步a, y步b可以由A走到B, 则有a*x+b*y=B-A;(第三种走法a+b相当于走了相同步数的a和b)若能此方程有整数解, 则可以由A走到B, 反之不能;那么, 接下来就是求|x|+|y|的最小值;
判断方程是否有解可以通过扩展欧几里得判断, 同时也可以求出通解;
若(B-A)%gcd(a, b)==0则方程有解, 反之无解;
根据扩展欧几里得可以求得x=x+bt, y=y-at;(t为任意整数);
emmmmm~数学知识太匮乏了, 到了这就不会继续向下算了只好去搜题解;
|x|+|y|最小值在x=x+bt与y=y-at两条直线交点附近;
#include <iostream>
#include <algorithm>
#include <string.h>
#include <stdio.h> 
#include <math.h>
using namespace std;
const long long inf = 0x3f3f3f3f;
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 r=exgcd(b, a%b, x, y);
	long long t=x;
	x=y;
	y=t-a/b*y;
	return r;
}
int main(){
	int T;
	cin >> T;
	while(T--){
		long long A, B, C;
		cin >> A >> B;
		long long a, b;
		cin >> a >> b;
		long long x, y;
		long long r;
                //求出a, b的最大公约数;
                r=exgcd(a, b, x, y);
		C=B-A;
                //判断是否有解;
                if(C%r) cout << -1 << endl;
		else{
			x*=C/r;
			y*=C/r;
			a/=r;
			b/=r;
			long long ans=inf*inf, tmp;
			long long mid=(y-x)/(a+b);//mid为两条直线交点;
			for(long long T=mid-1; T<=mid+1; T++){
				if((x+b*T)*(y-a*T)>=0)//x, y同号, 说明向同方向走, 走x步a, y步b, 由于还可以走a+b步, 所以可以走max(x, y)步;
					tmp=max(abs(x+b*T), abs(y-a*T));
				else//x, y异号, 说明向相反方向走, 走了x+y步;
					tmp=abs(x-y+(a+b)*T);
				ans=min(ans, tmp);
			}
			cout << ans << endl;
		}
	}
	return 0;
}




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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值