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

来源:互联网 发布:union软件安卓版 编辑:程序博客网 时间:2024/04/30 04:47

There is an interesting and simple one person game. Suppose there is a number axis under your feet. You are at pointA 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 bya,b and 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 integersA, B, a and b, separated by spaces. (-231A, B < 231, 0 < a, b < 231)

Output

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

Sample Input

20 1 1 20 1 2 4

Sample Output

1-1

题意是在数轴上给出两个点 再给你能走的距离 a, b, a+b (向左或向右都可以), 问最少需要多少步可以从一个点走到另一个点。不能到达输出-1

此题是扩展欧几里得问题。

我们可以设 走了x步a,走了y步b, ax + by = |A-B|,  扩展欧几里得解出x和y就是可行答案 但不一定是最少的步数。

现在可以假设如果x和y都是正的,也就是说不往回走,这样可以利用题目给的a+b步数进行优化,不管怎么样结果是x和y的较大值,那么假设x = y, 如果x减小,那么y一定增大 因为总路程是不变的,y减小同理,因此可以认为 x = y的时候 两者的较大值最小。

假设x小于0,y大于0,也就是x步往回走,y步正向走。那么这个结果就是abs(x) + abs(y),如果x继续减小说明往回走的多了 相应的y应该增大 那么最后的结果是增大的。

也就是说 x要尽量的增大 y要尽量的减小,可以理解为x与y最接近的时候取得最小步数。

综上两种情况 (x大于0 y小于0 类似第二种) 可以得到最小值的取得在 x == y 处。 但是可能这个点不存在,就要取他的附近两个点作比较,因为扩展欧几里得的特解求出之后 通解是可以求出的。


#include <algorithm>#include <iostream>#include <sstream>#include <cstring>#include <cstdlib>#include <cstdio>#include <vector>#include <cmath>#include <queue>#include <set>#include <map>#define mod 4294967296#define MAX 0x3f3f3f3f#define lson o<<1, l, m#define rson o<<1|1, m+1, r#define INFL 0x3f3f3f3f3f3f3f3fLL#define mem(a) memset(a, 0, sizeof(a))const double pi = acos(-1.0);const double eps = 1e-9;const int N = 10005;typedef long long ll;using namespace std;ll a, b, st, en;void exgcd(ll a, ll b, ll& d, ll& x, ll& y) {    if(!b) { d = a; x = 1; y = 0; }    else { exgcd(b, a%b, d, y, x); y -= x*(a/b); }}ll cal(ll x, ll y) {    if(x * y > 0) return max(abs(x), abs(y));    else return abs(x) + abs(y);}int main() {    //freopen("in.txt", "r", stdin);    int T;    cin >> T;    while(T--) {        cin >> st >> en >> a >> b;        ll len = abs(st-en);        ll d, x, y;        exgcd(a, b, d, x, y);        if(len % d) {            puts("-1");            continue;        }        x = x*len/d;        y = y*len/d;        ll t = (y-x)/(a/d + b/d);        ll ans = cal(x + t * (b/d), y - t * (a/d));        ans = min(ans, cal(x + (t+1) * (b/d), y - (t+1) * (a/d)));        ans = min(ans, cal(x + (t-1) * (b/d), y - (t-1) * (a/d)));         cout << ans << endl;    }    return 0;}

 



0 0
原创粉丝点击