标签:
题目:
Description
Input
Output
1. You can measure dmg using x many amg weights and y many bmg weights. 2. The total number of weights (x + y) is the smallest among those pairs of nonnegative integers satisfying the previous condition. 3. The total mass of weights (ax + by) is the smallest among those pairs of nonnegative integers satisfying the previous two conditions.
Sample Input
700 300 200 500 200 300 500 200 500 275 110 330 275 110 385 648 375 4002 3 1 10000 0 0 0
Sample Output
1 3 1 1 1 0 0 3 1 1 49 74 3333 1
这个题目相对比较难理解,我不解释题意,但是我用精确的语言重新表述以供参考。
输入a,b,d,求所有满足±a*x ±b*y =d的非负整数二元组(x,y)中,x+y最小的那一组,输出x和y。
如果这样的x和y不止一组,输出a*x+b*y最小的一组。
(题目所给数据保证上述二元不定方程一定有解)
这个题目,明显还是要用拓展欧几里得算法,不过还需要一个策略在无穷个解中找出最小解。
这里,需要了解拓展欧几里得算法的解空间结构。
可能你已经知道,如果方程有解,一定有无穷多个解,但是这无穷多个解在二维平面内是怎么分布的呢?
这是我随手画的示意图,能看懂就行。
像这种在y轴上面的截距的绝对值大于x轴上面的截距的绝对值的直线,
最小解要么是x轴上面最低的点A,要么是x轴下面最高的点B,需要比较才知道。
有了这个观念,这个题目就可以解决了。
代码:
#include<iostream> #include<stdio.h> using namespace std; long long x, y; long long gcd(long long a, long long b) { if (a == 0 || b == 0) { x = (b == 0); y = (a == 0); return a + b; } long long r; if (a < 0) { r = gcd(-a, b); x *= -1; return r; } if (b < 0) { r = gcd(a, -b); y *= -1; return r; } if (a >= b)r = gcd(a%b, b); else r = gcd(a, b%a); y -= a / b*x; x -= b / a*y; return r; } long long getabs(long long x, long long y) { long long x1 = x, y1 = y; if (x1 < 0)x1 = -x1; if (y1 < 0)y1 = -y1; return x1 + y1; } void f(long long a, long long b, long long d) { if (a > b) { f(b, a, d); long long t = x; x = y; y = t; return; } long long g=gcd(a, b); x *= d / g; y *= d / g; while (x < 0) { x += b / g; y -= a / g; } while (x - b / g >= 0) { x -= b / g; y += a / g; } if (getabs(x, y) > getabs(x - b / g, y + a / g)) { x -= b / g; y += a / g; } } int main() { long long a, b, d; while (cin >> a >> b >> d) { if (a == 0)break; f(a, b, d); long long x1 = x, y1 = y; if (x1 < 0)x1 = -x1; if (y1 < 0)y1 = -y1; f(a, b, -d); if (x < 0)x = -x; if (y < 0)y = -y; if (x1 + y1 < x + y)cout << x1 << " " << y1; else if (x1 + y1 > x + y)cout << x << " " << y; else { if (a*x1 + b*y1 < a*x + b*y)cout << x1 << " " << y1; else cout << x << " " << y; } cout << endl; } return 0; }
f函数里面的2个循环就是一步步平移到A,由A可以得到B,最后比较哪个较小。
HDU - 1356 The Balance(拓展欧几里得算法的解空间结构)
标签:
原文地址:http://blog.csdn.net/nameofcsdn/article/details/52253416