双六游戏 扩展欧几里得
/*
题目描述 :
一个双六上面有向前 向后无限延续的格子, 每个格子都写有整数。其中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 }