ZOJ 3593 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,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 integers A, 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 point B, output "-1" instead.

Sample Input

2
0 1 1 2
0 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 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#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;
}

 




你可能感兴趣的:(ACM__数论,ACM__数学)