1. 程式人生 > >數學問題的解題竅門——輾轉相除法

數學問題的解題竅門——輾轉相除法

輾轉相除法

求最大公約數

問題:線上格點的個數

給定平面上兩個格點(格點是指縱橫座標都為整數的點) P 1 = ( x 1

, y 2 ) , P 1 = (
x 2 , y 2 ) P_1=(x_1,y_2),P_1=(x_2,y_2) ,線段 P 1 P 2 P_1P_2 上,除了 P 1 P 2 P_1,P_2 還有多少個格點??

限制條件:

1 0 9 x 1 , x 2 , y 1 , y 2 1 0 9 -10^9\leqslant x_1,x_2,y_1,y_2 \leqslant 10^9

輸入樣例:

p1= 1 11   
p2= 5 3

輸出樣例:

(2,9) (3,7) (4,5)
3個格點

這道題目解答並不困難,首先我們立馬就能想到尋找 x 1 x 2 x_1和x_2 之間的整數、 y 1 , y 2 y_1,y_2 間的整數。然後檢查所有的點是否在直線 P 1 P 2 P_1P_2 上。雖然可以求出答案,但是時間複雜度較大,並不是一個好辦法。

這個題目其實可以利用最大公約數求解。

求a,b最大公約數的輾轉相除法:

  1. x=max(a,b) y=min(a,b)
  2. y=x%y ,x=y
  3. 如果y!=0 ,則重複步驟2否則最大公約數為x

編寫函式:

//求最大公約數的遞迴演算法
int gcd(x,y){   //x>=y
	if(y==0)return x;
	return gcd(y,x%y);
}

本題中所求的格點個數= ( x 1 x 2 y 1 y 2 ) 1 (|x_1-x_2|與|y_1-y_2|的最大公約數)-1

為啥最大公約數-1就是格點的個數呢??
以本題的示例輸入為例,可以這樣考慮:
8,4的最大公約數是4,說明8%4=0,4%4=0;
所以8和4都可以均分為4份,如下圖所示:

在這裡插入圖片描述

將橫縱座標都4等分,發現線上段內正好有三個點,而且每個點的橫縱座標都是整數,所以就有三個格點。
在這裡插入圖片描述

在本例中|x_1-x_2|=4與|y_1-y_2|=8,最大公約數為4,所以有3個格點。

程式碼如下;

#include <iostream>

using namespace std;

//最大公約數
int gcd(int x, int y) {
    if (y == 0) {
        return x;
    }
    return gcd(y, x % y);
}

//輸出格點
string printGridPoint(int x, int y) {
    return "(" + to_string(x) + "," + to_string(y) + ")";
}

int main() {

    int x1, y1, x2, y2;
    cout << "P1=";
    cin >> x1 >> y1;
    cout << "P2=";
    cin >> x2 >> y2;

    int x = max(abs(x1 - x2), abs(y1 - y2));
    int y = min(abs(x1 - x2), abs(y1 - y2));
    int num = gcd(x, y);

    int stepX = (x1 - x2) / num;
    int stepY = (y1 - y2) / num;

    for (int i = 1; i < num; i++) {
        cout << printGridPoint(x2 + stepX * i, y2 + stepY * i) << " ";
    }
    cout << endl;

    cout << (num - 1) << "個格點";


}