扩展GCD的运用

来源:互联网 发布:淘宝店铺css代码 编辑:程序博客网 时间:2024/05/05 02:34



题目连接:http://acm.jlu.edu.cn/joj/upload/jlp2011.pdf
Problem B: Xiao Ming’s Computer 
Xiao Ming is a clever boy who invented a strange computer named "Xiao Ming 
Computer". The computer has only 4 kinds of instructions: Y+=a; Y-=a; Y+=b; Y-=b; (a, 
b are two determined integers). This computer is simple, but can do many interesting 
things. Xiao Ming found that when a, b are coprime (that their greatest common 
divisor is 1), this computer is complete on addition and subtraction. 
For example, when a = 3 and b = 5, Xiao Ming would like to use this machine to 
achieve +1 operation. It can be done by the following two programs. 
Program 1: 
Y-=5; 
Y+=3; 
Y+=3; 
Program 2: 
Y+=5; 
Y-=3; 
Y-=3; 
Y-=3; 
Y+=5; 
Of course, there are many other ways to achieve. It can be proven that the first 
program is shortest. 
Xiao Ming now wants to test the performance of the machine. Can you write a 
program to turn any integer into 0 by this "Xiao Ming computer"? Furthermore, this 
program should be shortest among all correct programs. 
For example, the above two program can turn -1 to 0. And the shortest program 
executes 3 instructions. 
Input 
The first line of each case are three integers n, a, b. Here a, b (-60000≤ a, b 
≤ 60000, a≠ 0, b≠0, and gcd(a,b)=1) are the two numbers "Xiao Ming 
computer" can add or subtract. Followed by n (n<=100) lines is a 32-bit integer X 
that you should test.

Output 
For each case, the first output line "Computer" + case number +":"( starting 
with 1). Then for every X, output the least number of operations to turn it into 0.
Sample Input 
1 3 5 
2 3 7 
Sample Output 
Computer 1: 
Computer 2: 

题目大意;
本题就是求一个 n*a+m*b=c 的一组解使得| n|+|m| 尽可能的小!
资料:看到此题,开始想暴力,结果发现自己错了;其实这是一道数论题。运用到扩展GCD,求出一个特解,x0,y0;在有d=gcd(a,b),a0=a/d,b0=b/d;那么可以求出通解x=x0+a0*t;y=y0-b0*t;(a0>0,b0>0,t为整数)
不妨设a0>b0,可以证明|n|+|m|最小时有 -b
题目分析:

呼呼~~通过这个题,终于对线性同余方程有一定的了解了。呼呼~~

 

题目要我们求解方程 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



题目连接:http://acm.jlu.edu.cn/joj/upload/jlp2011.pdf


原创粉丝点击