呼呼~~通过这个题,终于对线性同余方程有一定的了解了。呼呼~~
题目要我们求解方程 a * x + b * y = c ----方程[1]。
我们可以先求解方程a * x1 + b * y1 = gcd(a, b) = d。-----方程[2] 。
用扩展欧几里德就可以求出x1, y1(特解), 要使方程[2]变回方程[1], 只需要对方程[2]的两边同时除以d再乘以c就可以了。即: x0 = x1 * c / d, y0 = y1 * c / d。
对于有解的线性同余方程 a * x + b * y = c, 必定能够找到一组x0, y0, 使得
a * x + b * y = c = a * x0 + b * y0
进而得 a * (x - x0) = b * (y0 - y), d = gcd(a, b)=1。
又(a / d) * (x - x0) = (b / d) * (y0 - y),那么 (b/d) | (x - x0) , 设 (x - x0) = t * b / d, 代人得 y0 - y = t * a / d。 这样,可以得出通解形式
x = x0 + b / d * t, y = y0 - a / d * t。
此题中d=1;
当有多组解时,要求输出(|x| + |y|)值最小的一组。即 (| x | + | y |)= | x0 + b / d * t | + | y0 - a / d * t | = f(t), 简单分析,可以知道, | x0 + b / d * t | 永远递增且大于零。f(t) 只有在 | y0 - a / d * t | == 0的时候 才能取得最小值。又因为 t 是整数,所以 t 应该取 (y0 * d / a) 左右的整数值。
代码如下:
#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdlib>
#include <vector>
#include <queue>
#include <cstdio>
#include <cmath>
#include <string>
#include <stack>
#include <cctype>
using namespace std;
int ex_gcd(int a, int b, int & x, int & y)
{
if (b == 0)
{
x = 1;
y = 0;
return a;
}
int ret = ex_gcd(b, a % b, x, y);
int t = x;
x = y;
y = t - a / b * y;
return ret;
}
int main()
{
int kk=0;
int n,a,b,c;
bool flag = 0;
while (~scanf("%d%d%d",&n,&a,&b))
{
kk++;
printf("Computer %d:\n",kk);
while(n--)
{
scanf("%d",&c);
flag = 0;
if (a < b)
{
swap(a, b);
flag = 1;
}
int x0, y0, x, y,t, f1, f2, w1, w2;
ex_gcd(a, b, x0, y0);
x0 *= c;
y0 *= c;
t = y0/a;
if (t *a-y0>= 0)
--t;
f1 = abs(x0 + b*t) + abs(y0- a* t);
f2 = abs(x0 + b*(t + 1)) + abs(y0 - a* (t + 1));
if (f2 < f1)
t += 1;
else if (f2 == f1)
{
x = abs(x0 + b * t);
y = abs(y0 - a* t);
w1 = a * x + b * y;
x = abs(x0 + b* (t + 1));
y = abs(y0 - a* (t + 1));
w2 = a * x + b * y;
if (w2<w1)
t+=1;
}
int anss=abs(x0+b*t)+abs(y0-a*t);
printf("%d\n", anss);
}
}
return 0;
}
类似题目
poj2142 http://poj.org/problem?id=2142