第六章 數學問題 -------- 6.9 天平稱重問題【線性同餘方程】青蛙的約會

Curtis_發表於2019-03-22

模運算:

  取模:計算除以m的餘數,叫做對m取模

  同餘:將a,b對m取模的結果相同,記為 a ≡ b (mod m)(例如: x % 3 = 2  ===>  x ≡ 2(%3),x餘3等於2,和2同餘),即 a mod m == b mod m  如果 a ≡ b (mod m),且c ≡ d (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。

  然後根據上面寫程式碼即可:

import java.util.Scanner;

// 求解同餘方程的本質就是求線性方程
// 將求餘方程轉化為線性方程
public class 青蛙的約會 {
    
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        long x = scanner.nextInt();  // 座標
        long y = scanner.nextInt();  // 座標
        long m = scanner.nextInt();  // A第一次跳
        long n = scanner.nextInt();  // B第一次跳
        long l = scanner.nextInt();  // 維度總長
        
        long a = m-n;
        long b = l;
        m = y-x;
        long d = 0;
        try {
            d = ExtGcd.linearEquation(a, b, m);
        } catch (Exception e) {
            System.out.println("Impossible");
        } // 求解線性方程
        long x0 = ExtGcd.x;
        b /= d;  // 約一下
        b = Math.abs(b);  // 有可能小於0
        /*=========這裡是AC的關鍵===========*/
        x0 = (x0%b+b)%b; // 要求大於0的第一個解
        System.out.println(x0);
    }
    
    // 私有的靜態的內部類
    private static class ExtGcd{
        static long x,y;
        
        public static long ext_gcd(long a,long b){
            if (b==0) {
                x = 1;
                y = 0;
                return a;
            }
            long res = ext_gcd(b, a%b);
            long x1 = x;
            x = y;
            y = x1-a/b*y;
            return res;
        }
        
        public static long linearEquation(long a,long b,long m) throws Exception{
            long d = ext_gcd(a, b);
            if(m%d!=0) throw new Exception("無解");
            long n = m / d;
            x *= n;
            y *= n;
            return d;
        }
    }
}

  結果:

 

相關文章