POJ 2142 - The Balance [ 扩展欧几里得 ]

题意:

  给定 a b n找到满足ax+by=n 的x,y 令|x|+|y|最小(等时令a|x|+b|y|最小)

分析:

  算法一定是扩展欧几里得。

  最小的时候一定是 x 是最小正值 或者 y 是最小正值

    (简单的证明应该是分x,y 符号一正一负,和x,y符号都为正来考虑)

  

  扩欧解的方程为 ax+by = gcd(a, b)

  先简化问题,等价为扩欧求的是 a‘x+b‘y = 1

  则原方程等价为 a‘x+b‘y = n‘ (a, b, n 全部除以gcd(a, b) )

  先解x为最小正值的时候

      x = (x % b‘ + b‘) % b‘

    此时y = (n‘ - x*a) / b

  考虑 y时同理。

  

 1 #include <iostream>
 2 #include <cstdio>
 3 #include <cstring>
 4 using namespace std;
 5 int abs(int x)
 6 {
 7     return x > 0 ? x : -x;
 8 }
 9 int ExtGcd(int a, int b, int& x, int& y)
10 {
11     if (b == 0) { x = 1; y = 0; return a;}
12     int d = ExtGcd(b, a%b, y, x);
13     y -= a/b*x;
14     return d;
15 }
16 int a, b, d;
17 int main()
18 {
19     while (~scanf("%d%d%d", &a, &b, &d) && (a+b+d))
20     {
21         int x, y;
22         int gcd = ExtGcd(a, b, x, y);
23         a /= gcd;//简化问题
24         b /= gcd;
25         d /= gcd;
26         x *= d;
27         x = (x%b+b) % b;//x大于0的最小值
28         y = (d-x*a) / b;//对应 y
29         int ans1 = abs(x), ans2 = abs(y);
30         y = (y%a+a) % a;
31         x = (d-y*b) / a;
32         int x0 = abs(x);
33         int y0 = abs(y);
34         if (x0+y0 < ans1+ans2 ) ans1 = x0, ans2 = y0;
35         else if (x0+y0==ans1+ans2 && a*x0+b*y0 < a*ans1+b*ans2) ans1 = x0, ans2 = y0;
36         printf("%d %d\n", ans1, ans2);
37     }
38 }
39 //
时间: 2024-10-01 21:04:57

POJ 2142 - The Balance [ 扩展欧几里得 ]的相关文章

POJ 2142:The Balance_扩展欧几里得(多组解)

先做出两个函数的图像,然后求|x|+|y|的最小值.|x|+|y|=|x0+b/d *t |+|y0-a/d *t| 这个关于t的函数的最小值应该在t零点附近(在斜率大的那条折线的零点附近,可以观察出来).以下三种情况中,函数最小值都应该出现在B点附近./* 对于不定整数方程xa+yb=c,若 c mod Gcd(a, b)=0,则该方程存在整数解,否则不存在整数解. 上面已经列出找一个整数解的方法,在找到x * a+y * b = Gcd(a, b)的一组解x0,y0后 ,/*x * a+y

POJ 2115 C Looooops(扩展欧几里得应用)

题目地址:POJ 2115 水题..公式很好推.最直接的公式就是a+n*c==b+m*2^k.然后可以变形为模线性方程的样子,就是 n*c+m*2^k==b-a.即求n*c==(b-a)mod(2^k)的最小解.(真搞不懂为什么训练的时候好多人把青蛙的约会都给做出来了,这题却一直做不出来.....这两道不都是推公式然后变形吗.....) 代码如下: #include <iostream> #include <cstdio> #include <string> #incl

POJ 2115 C Looooops(扩展欧几里得)

辗转相除法(欧几里得算法) 时间复杂度:在O(logmax(a, b))以内 int gcd(int a, int b) { if (b == 0) return a; return gcd(b, a % b); } 扩展欧几里得算法 时间复杂度和欧几里得算法相同 int extgcd(int a, int b, int& x, int& y) { int d = a; if (b != 0) { d = extgcd(b, a % b, y, x); y -= (a / b) * x;

POJ 2115 C Loooooops 扩展欧几里得

http://poj.org/problem?id=2115 题意:给出a,b,c<=1e9,k<=32 求出p 使得 (a+pc)mod2^k=ba+pc同余b(mod2^k) 2^kx=a+pc-b -> 2^kx-pc=a-b 利用exgcd求出x,p即可 最小正整数解x=x0+(k/d)*n 通解 任意解:x同余x0 mod(k/d) x0%(k/d)显然和x0同余(k/d)x=(x0%k/d+k/d)%mod 为最小正整数解 x0%k/d为正 x显然为最小正整数解 x0%k/d

poj 2142 扩展欧几里得

原题实际上就是求方程a*x+b*y=d的一个特解,要求这个特解满足|x|+|y|最小 套模式+一点YY就行了 总结一下这类问题的解法: 对于方程ax+by=c 设tm=gcd(a,b) 先用扩展欧几里得求出方程ax+by=tm的解x0.y0 然后有a*x0+b*y0=tm 令x1=x0*(c/tm),y1=y0*(c/tm) 则a*x1+b*y1=c x1.y1即原方程的一个特解 这个方程的通解:xi=x1+k*(b/m),yi=y1-k*(a/m) 另:如果要求yi的最小非负解?令r=a/tm

POJ 2115 (模线性方程 -&gt; 扩展欧几里得)

题意: for(i=A ; i!=B ;i +=C)循环语句,问在k位操作系统中循环结束次数. 若在有则输出循环次数. 否则输出死循环. 存在这样的情况:i= 65533 :i<=2:i+= 4:时i = 2: 由模线性方程->扩展欧几里得 #include <iostream> #include <cstdio> #include <cstdlib> #include <cstring> #include <queue> using

扩展欧几里得定理——POJ 1061

对应POJ 题目:点击打开链接 青蛙的约会 Time Limit: 1000MS   Memory Limit: 10000K Total Submissions: 94409   Accepted: 17470 Description 两只青蛙在网上相识了,它们聊得很开心,于是觉得很有必要见一面.它们很高兴地发现它们住在同一条纬度线上,于是它们约定各自朝西跳,直到碰面为止.可是它们出发之前忘记了一件很重要的事情,既没有问清楚对方的特征,也没有约定见面的具体位置.不过青蛙们都是很乐观的,它们觉得

POJ 1061 青蛙的约会 (扩展欧几里得)

原式 ax + by = c    =>  ax1 + by1 = gcd(a,b); a,b,c为任意整数,d = gcd(a,b),则  ax1 + by1 = d 的一组解是(x1,y1),c是gcd(a,b)的倍数时,其中的一组解为(x1*c/d,y1*c/d);c不是gcd(a,b)的倍数时,无解 青蛙的约会,就是一道例题 按照题意很容易列举出等式:(x+ms) - (y+ns) = k*l;  (k=1.....n)   变形到  扩展欧几里得公式  即可: #include <i

poj 1061(扩展欧几里得)

青蛙的约会 Time Limit: 1000MS   Memory Limit: 10000K Total Submissions: 90299   Accepted: 16412 Description 两只青蛙在网上相识了,它们聊得很开心,于是觉得很有必要见一面.它们很高兴地发现它们住在同一条纬度线上,于是它们约定各自朝西跳,直到碰面为止.可是它们出发之前忘记了一件很重要的事情,既没有问清楚对方的特征,也没有约定见面的具体位置.不过青蛙们都是很乐观的,它们觉得只要一直朝着某个方向跳下去,总能