zoukankan      html  css  js  c++  java
  • 双六游戏 扩展欧几里得

    /*
    题目描述 :
    一个双六上面有向前 向后无限延续的格子, 每个格子都写有整数。其中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 }
  • 相关阅读:
    string 流
    文件输入和输出
    IO类
    算法
    MySQL常用处理方法
    linux curl工具
    设计模式
    C语言编程流程
    js escape 与php escape
    js undefined易错分析
  • 原文地址:https://www.cnblogs.com/oscar-cnblogs/p/6428920.html
Copyright © 2011-2022 走看看