• 【线性同余方程】青蛙的约会


    模运算:

      取模:计算除以m的余数,叫做对m取模

      同余:将a,b对m取模的结果相同,记为 ≡ (mod m)(例如: x % 3 = 2  ===>  x ≡ 2(%3),x余3等于2,和2同余),即 a mod m == b mod m  如果 a ≡ (mod m),且c ≡ (mod m),则有 a+b ≡ c+d (mod m)  a*b ≡ c*d (mod m)

    线性同余方程: 

        a,b是整数,形如 ax ≡ b (mod n),且x是未知整数的同余式称为一元线性同余方程。
      定理:同余方程 ax ≡ b (mod n) 对于未知数 x 有解,当且仅当 b 是 gcd(a,n)的倍数。否则方程无解。且方程有解时,方程有 gcd(a,n)个解。
      这里根据取余的概念可以得出,假如 a%n = b 的话,可以写出一个等式 a = n*t +b; 
      求解线性同余方程的方法:这里根据上面很容易得出下面两个等式:

        ax = n*y1 + 余数   
        b = n*y2 + 余数

      上面两式相减得 ax - b = n(y1-y2)  ===>  ax - b = ny  ===> ax + ny = b; (这里的未知数x y不用管正负号,因为最后求解出来的结果x y自带正负号。)

      那么根据这个等式采用扩展欧几里得算法就能够得出 x 的值。也就解出了线性同余方程。

    例题:青蛙的约会

      

      思路:因为线总长L,青蛙需要循环跳才有可能碰面。而循环跳的话那么它们的位置只能通过对L取余得到(可以对比钟表转圈理解)。根据题意,假设它们需要跳k次才能碰面,那么很容易得出这个同余组x+k*m ≡ y+k*n (mod L)。根据上面的讲解我们也可以得到下面两个等式:

        x + k*m = L*t1 + 余数   
        y + k*n = L*t2 + 余数

      还是上面两式相减得到  x - y + (m-n)*k = L * t  ===> (m-n)*k + L * t = y - x  这里已知的变量有 m n L y x,所以未知的变量为 k t

      然后再对比扩展欧几里得算法求线性方程的等式 ax+by = m   所以可以得出 a = m -  n,b = L,m = y - x。

      然后根据上面写代码即可:

     1 import java.util.Scanner;
     2 
     3 // 求解同余方程的本质就是求线性方程
     4 // 将求余方程转化为线性方程
     5 public class 青蛙的约会 {
     6     
     7     public static void main(String[] args) {
     8         Scanner scanner = new Scanner(System.in);
     9         long x = scanner.nextInt();  // 坐标
    10         long y = scanner.nextInt();  // 坐标
    11         long m = scanner.nextInt();  // A第一次跳
    12         long n = scanner.nextInt();  // B第一次跳
    13         long l = scanner.nextInt();  // 维度总长
    14         
    15         long a = m-n;
    16         long b = l;
    17         m = y-x;
    18         long d = 0;
    19         try {
    20             d = ExtGcd.linearEquation(a, b, m);
    21         } catch (Exception e) {
    22             System.out.println("Impossible");
    23         } // 求解线性方程
    24         long x0 = ExtGcd.x;
    25         b /= d;  // 约一下
    26         b = Math.abs(b);  // 有可能小于0
    27         /*=========这里是AC的关键===========*/
    28         x0 = (x0%b+b)%b; // 要求大于0的第一个解
    29         System.out.println(x0);
    30     }
    31     
    32     // 私有的静态的内部类
    33     private static class ExtGcd{
    34         static long x,y;
    35         
    36         public static long ext_gcd(long a,long b){
    37             if (b==0) {
    38                 x = 1;
    39                 y = 0;
    40                 return a;
    41             }
    42             long res = ext_gcd(b, a%b);
    43             long x1 = x;
    44             x = y;
    45             y = x1-a/b*y;
    46             return res;
    47         }
    48         
    49         public static long linearEquation(long a,long b,long m) throws Exception{
    50             long d = ext_gcd(a, b);
    51             if(m%d!=0) throw new Exception("无解");
    52             long n = m / d;
    53             x *= n;
    54             y *= n;
    55             return d;
    56         }
    57     }
    58 }

      结果:

        

        

      

      

     

  • 相关阅读:
    (Java) LeetCode 275. H-Index II —— H指数 II
    (Java) LeetCode 82. Remove Duplicates from Sorted List II —— 删除排序链表中的重复元素 II
    前端知识体系目录
    PhoneGap/cordvoa如何添加Media插件
    使用Google Closure Compiler高级压缩Javascript代码注意的几个地方
    javascript中的函数式声明与变量式声明
    call,apply,bind的用法
    canvas学习笔记
    Cookie/Session机制详解
    架构师速成6.8-设计开发思路-领域驱动 分类: 架构师速成 2015-07-30 18:28 15人阅读 评论(0) 收藏
  • 原文地址:https://www.cnblogs.com/xiaoyh/p/10332380.html
Copyright © 2020-2023  润新知