數學問題的解題竅門——輾轉相除法
阿新 • • 發佈:2018-12-06
輾轉相除法
求最大公約數
問題:線上格點的個數
給定平面上兩個格點(格點是指縱橫座標都為整數的點) ,線段 上,除了 還有多少個格點??
限制條件:
輸入樣例:
p1= 1 11
p2= 5 3
輸出樣例:
(2,9) (3,7) (4,5)
3個格點
這道題目解答並不困難,首先我們立馬就能想到尋找 之間的整數、 間的整數。然後檢查所有的點是否在直線 上。雖然可以求出答案,但是時間複雜度較大,並不是一個好辦法。
這個題目其實可以利用最大公約數求解。
求a,b最大公約數的輾轉相除法:
- x=max(a,b) y=min(a,b)
- y=x%y ,x=y
- 如果y!=0 ,則重複步驟2否則最大公約數為x
編寫函式:
//求最大公約數的遞迴演算法
int gcd(x,y){ //x>=y
if(y==0)return x;
return gcd(y,x%y);
}
本題中所求的格點個數=
為啥最大公約數-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) << "個格點";
}