双六游戏 扩展欧几里得

/*
题目描述 :
一个双六上面有向前 向后无限延续的格子, 每个格子都写有整数。其中0号格子是起点,1号格子
是终点。而骰子上只有a,b,-a,-b四个整数,所以根据a和b的值的不同,有可能无法到达终点
掷出四个整数各多少次可以到达终点呢?如果解不唯一,输出任意一组即可。如果无解 输出-1

*/

问题就是求 ax+by = c的通解

证明一: 一定存在 x, y 使得 ax+by = kgcd(a, b) 

 设 a = gcd(a, b)*ra; b = gcd(a, b)*rb;

∵gcd(ra, rb) = 1

∴ax+by = (x*ra+y*rb)*gcd(a, b) = kgcd(a, b) ----->k = (x*ra+y*rb)

有∵ gcd(ra, rb) = 1 由贝祖定理 一定存在 x, y  (x*ra+y*rb = gcd(ra, rb) = 1)

http://baike.sogou.com/v73423552.htm?fromTitle=%E8%A3%B4%E8%9C%80%E5%AE%9A%E7%90%86  -->贝祖定理

 

所以题目中的c = 1

1、那么一定要 a 和b互质 才能得到1

2、ax+by = 1是一个不定方程 

对于求其中的一组特解  可以使用 扩展欧几里得

extgcd(int a, int b, int &x, int &y)

对于求 gcd(a, b) 那么由辗转相除法一定有 gcd(b, a%b)

第一层:ax1+by1     -->  第二层:bx2+(a%b)y2 = gcd(b, a%b) = gcd(a, b).....x1, y1, x2, y2表示两层的x 和 y

两层的x 和 y有什么联系呢  -->通过a 和 b的变化联系

因为 a%b = a-(a/b)*b ---> 第二层:a*y2 + b*(x2-(a/b)*y2) = gcd --->对应第一层 a*x1 + b*y1 = gcd

所以有: x1 = y2,  y1 = (x2-(a/b)*y2) ....得到了两层x, y的关系 可以由此递推

结束条件:

最终a = gcd, a%b = 0   --> ax+by = gcd --> x = 1 , y = 0

所以 if(b == 0) 

{  x = 1; y = 0; return a; }

得到 一组特解 x, y

 1 int extgcd(int a, int b, int &x, int &y)
 2 {
 3     if (b == 0)
 4     {
 5         x = 1;
 6         y = 0;
 7         return a;
 8     }
 9     int ans = extgcd(b, a%b, x, y);
10     int tmp = x;
11     x = y;
12     y = tmp - a/b*y;
13     return ans;
14 }

补充求通解 

方程 ax+by = c ....①

已知特解ax0+by0 = c ...②

①-② -->a(x-x0) + b(y-y0) = 0

---> ra*gcd(a,b)*(x-x0) + rb*gcd(a,b)*(y-y0) = 0

--->ra*(x-x0) + rb*(y-y0) = 0

有ra*(x-x0) = rb*(y0-y)

又∵ gcd(ra, rb) = 1

∴ x-x0 = k*b/gcd(a, b) --> x = x0+k*b/gcd(a,b)

同理y = y0-k*a/gcd(a,b)

题目代码

 1 #include <iostream>
 2 #include <stdio.h>
 3 #include <string.h>
 4 #include <queue>
 5 #include <algorithm>
 6 #define READ() freopen("in.txt", "r", stdin);
 7 #define MAXV 2007
 8 #define MAXE 20007
 9 #define INF 0x3f3f3f3f3f3f3f3f
10 using namespace std;
11 //扩展欧几里得
12 
13 int extgcd(int a, int b, int &x, int &y)//c++的引用代入 也可以用指针
14 {
15     if (b == 0)
16     {
17         x = 1;
18         y = 0;
19         return a;
20     }
21     int ans = extgcd(b, a%b, x, y);
22     int tmp = x;
23     x = y;
24     y = tmp - a/b*y;
25     return ans;
26 }
27 //更简洁的写法 书上的 直接将y传到x的位置 x传到y的位置然后y再-a/b*y
28 int Extgcd(int a, int b, int &x, int &y)
29 {
30     int d = a;
31     if (b != 0)
32     {
33         d = Extgcd(b, a%b, y, x);
34         y -= a/b*x;
35     }
36     else
37     {
38         x = 1;
39         y = 0;
40     }
41     return d;
42 }
43 
44 int main()
45 {
46     READ()
47     int a, b, x, y;
48     int cnt[4] = {0};
49     scanf("%d%d", &a, &b);
50     if (extgcd(a, b, x, y) != 1)
51     {
52         cout << -1 << endl;
53         return 0;
54     }
55     if (x > 0) cnt[0] = x;
56     else if (x < 0) cnt[2] = -x;
57     if (y > 0) cnt[1] = y;
58     else if (y < 0) cnt[3] = -y;
59     for (int i = 0; i < 4; i++) cout << cnt[i];
60 //    else cout << x << " " << y << endl;
61     cout << endl;
62     return 0;
63 }

 

posted @ 2017-02-22 14:47  Lorazepam  阅读(877)  评论(0编辑  收藏  举报