欧几里得算法
思想:
欧几里德算法又称辗转相除法,是指用于计算两个a,b的最大公约数。计算公式gcd(a,b) = gcd(b,a mod b)。补充一个知识点(最小公倍数等于a*b/gcd(a,b))
证明就不证明了,这个记住的话也挺简单的
代码如下:
#include <iostream>
#include <cstdio>
using namespace std;
int gcd(int a,int b){
return b==0?a:gcd(b,a%b);
}
int main() {
printf("%d\n",gcd(4,16));
return 0;
}
扩展欧几里得算法
思想:
找出一对整数x,y,使它满足方程ax+by = gcd(a, b),其中x和y可能等于或者小于0,例如gcd(6,15)=3,6*3-15*1=3,则x=6,y=-1。还有一组解就是x=-2,y=1。
代码如下:
#include <iostream>
#include <cstdio>
using namespace std;
int exgcd(int a,int b, int &x, int &y){
if(!b) {
x = 1; y = 0;
return a;
}
int r = exgcd(b,a%b,x,y); //这个就是a与b的最大公倍数
int tmp = x;
x = y;
y = tmp - a/b*y;
return r;
}
int main() {
int x,y;
exgcd(6,15,x,y);
printf("%d %d\n",x,y);
return 0;
}
程序怎样理解呢?我们要用递归,使得下一个x,y得到上一个x,y //这个是重点
1、我们首先想到终点的b=0的时候,gcd(a,b) = a,此时想要ax+by = gcd(a, b),只有当x=1,y=0的时候才能实现,即a*1+b*0 = a。
2、那之后怎样理解呢? 首先已知ax+by = gcd(a, b), 则由于欧几里得得到 bx1+(a%b)y1 = gcd(b,a%b).
又因为gcd(b,a%b)=gcd(a, b)。得到ax+by = bx1+(a%b)y1。 而a%b在计算机中可以表示为a - (a/b)*b(这个自己想,整形问题)
3、那么ax+by = bx1+(a-(a/b)*b)y1。 又bx1+(a-(a/b)*b)y1 = ay1+bx1-(a/b)by1。
4、最后得到 x = y1; y = x1-(a/b)y1。
下面我们来一到例题
题目链接:hdu1576 A÷B
题目大意:
A/B
Time Limit: 1000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 7362 Accepted Submission(s): 5844
Problem Description
要求(A/B)%9973,但由于A很大,我们只给出n(n=A%9973)(我们给定的A必能被B整除,且gcd(B,9973) = 1)。
Input
数据的第一行是一个T,表示有T组数据。
每组数据有两个数n(0 <= n < 9973)和B(1 <= B <= 10^9)。
每组数据有两个数n(0 <= n < 9973)和B(1 <= B <= 10^9)。
Output
对应每组数据输出(A/B)%9973。
Sample Input
2
1000 53
87 123456789
Sample Output
7922
6060
题目分析:
第一次做这种题目应该是一脸蒙蔽,毕竟这是数学题嘛,我就直接给出推论
1、n=A%9973 => n=A-A/9973*9973
2、A/B=X => A=BX
3、设-A/9973为Y;得出 BX+9973Y=n 所以我们求出X就知道A/B了,最后只要%9973就能得出答案
4、而已知Bx+9973y = 1(题目gcd(B,9973) = 1) =》 Bxn+9973yn = n
5、xn == X了
题解:
#include <iostream>
#include <cstdio>
using namespace std;
void exgcd(int a, int b, int &x, int &y) {
if(!b) {
x = 1; y = 0;
return ;
}
exgcd(b,a%b,x,y);
int tmp = x;
x = y;
y = tmp - a/b*y;
}
int main() {
int t;
scanf("%d",&t);
for(int i = 0; i < t; i++) {
int n,b,x,y;
scanf("%d%d",&n,&b);
exgcd(b,9973,x,y);
printf("%d\n",(((x%9973+9973)%9973)*(n%9973))%9973);//%这么多9973是为了防止超出int,而前面那个(x%9973+9973)%9973是防止x为负数
}
return 0;
}
下面抛出两道题目给读者练习,答案会在写了之后贴在这里哟
POJ1061 青蛙的约会 、 NYOJ1013 除法表达式
如果有眼前一亮的题目或者解答欢迎和楼主讨论 ε=ε=ε=┏(゜ロ゜;)┛ 楼主的QQ486291187.