2021-07-11

9 篇文章 0 订阅
1 篇文章 0 订阅

One Person Game
There is an interesting and simple one person game. Suppose there is a number axis under your feet. You are at point A at first and your aim is point B. There are 6 kinds of operations you can perform in one step. That is to go left or right by a,band c, here c always equals to a+b.

You must arrive B as soon as possible. Please calculate the minimum number of steps.

Input

There are multiple test cases. The first line of input is an integer T(0 < T ≤ 1000) indicates the number of test cases. Then T test cases follow. Each test case is represented by a line containing four integers 4 integers A, B, a and b, separated by spaces. (-231 ≤ A, B < 231, 0 < a, b < 231)

Output

For each test case, output the minimum number of steps. If it's impossible to reach point B, output "-1" instead.

Sample Input

2
0 1 1 2
0 1 2 4

Sample Output

1
-1

————————————————
题目的大意是说有三种操做方式,每一次可以移动距离a或者移动距离b或者一次性移动a+b;由于有正反两种方向,所以相当于有6种操作。
起点和终点是等价的,从起点到终点和终点到起点是互逆的过程。所以我们用ax+by=abs(A-B)方程来求解,由于a+b是a和b的线性组合,所以一次性移动a+b的情况也被考虑进来(不妨假设它先移动a再移动一次b)。
通过分析我们不难发现只有两种情况:

1、x,y都是非负方向的,这时候我们知道,min(x,y)可以合并成a+b步。所以我们的答案就算max(x,y);
2、x和y是相反的。这种情况下一定是先以a(b)移动对应步数,然后返回时以b(a)移动对应步数,不存在有a+b的情况,假设有a+b出现在正向移动的过程中,那么折返时,必然也会出现a和b,这样必然会与前面的所有a+b的情况抵消,否则就得归为第一类情况.所以ans=abs(x)+abs(y);

讨论完上面情况:
1、当1时x+y取最小,有均值不等式得,x和y最接近时可能去最小。枚举x=y的前后两点和本身,一定包含极限情况
2、可以假设某种状态为abs(x)+abs(y)最小
在这里插入图片描述如果黑色的线代表了最优解,那么蓝色的线不可能存在,只可能还有红色线表示的解。所以我们得到结论:出现最优解时,abs(x)最小,abs(y)最小。

所以上代码:

#include<bits/stdc++.h>
using namespace std;
int gcd(int a,int b){
	return b==0?a:gcd(b,a%b);
}
int exgcd(int a,int b,int &x,int &y){
	if(b==0){
		x=1;
		y=0;
		return a;
	}
	int t=exgcd(b,a%b,x,y);
	int tx=x;
	x=y;
	y=tx-a/b*y;
	return t;
}
int  solve(int a,int b,int c){
	int q=gcd(a,b);
	if(c%q!=0){
		return -1;
	}
	int x,y;
	int ans=1e8;
	a/=q,b/=q,c/=q;
	q=exgcd(a,b,x,y);
	x*=c;
	y*=c;//现在知道对于每一种情况而言都是x与y趋近时取得最优解 
	int k=(y-x)/(a+b);//当x,y相等时的k(相对于求出来的初始x0,y0而言),由于是整数,所以不一定就是这个值,枚举它附近的点
	for(int i=k-1;i<=k+1;i++){
		if(abs(x+b*i)+abs(y-a*i)==abs(x+b*i+y-a*i))
			ans=min(ans,max(x+b*i,y-a*i));
		else
			ans=min(ans,abs(x+b*i)+abs(y-a*i));	//这个由绝对值不等式得出 
	} 
	return ans;
}
int main(){
	int t;
	cin>>t;
	while(t--){
		int A,B,a,b,c;
		cin>>A>>B>>a>>b;
		c=abs(A-B);
		int  ans=solve(a,b,c);
		cout<<ans<<endl;
	}
	return 0;
}
注:y=y0-a*k
x=x0+b*k
当x=y时
x0+b*k=y0-a*k;
k=(y0-x0)/(a+b);
  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值