在这里要注意一点的就是乘法逆的求法:
求a关于n的乘法逆的方法就是利用扩展的欧几里得算法求解:
s * n + a * t = 1 (gcd(n,a) = 1才存在乘法逆)
实现代码如下:
int gcd(int x,int y){
return y == 0 ? x : gcd(y,x%y);
}
void exEuclidean(int a,int b,int &s,int &t){
int r1 = a, r2 = b , s1 = 1, s2 = 0, t1 = 0, t2 = 1;//初始化
int q,r;
while(r2 > 0)
{
q = r1 / r2;
r = r1 - q * r2; //也就是r = r1%r2;
r1 = r2;
r2 = r;
s = s1 - q * s2;
s1 = s2;
s2 = s;
t = t1 - q * t2;
t1 = t2;
t2 = t;
}
//gcd(a,b) = r1;
s = s1;
t = t1;
}
int main()
{
int a,n,b;
printf("请依次输入ax %% n = b方程中的系数 a , n ,b!\n");
//其实就是ax = kn + b ,也就是 ax + nk = b-------线性丢番图方程
scanf("%d %d %d",&a,&n,&b);
int gcd_a_n = gcd(a,n);
if(b%gcd_a_n != 0){
//根据线性丢番图方程 ax + by = c中如果gcd(a,b)不能整除c的话,无解
printf("gcd(a,n)不能整出b,该方程无解\n");
}
else{ //有解
//(1)除以gcd_a_n,简化方程
a /= gcd_a_n;
n /= gcd_a_n;
b /= gcd_a_n;
//(2)乘以a的乘法逆,找出方程特解x0
//利用扩展的欧几里得算法求 n * s + a * t = 1(注意:1是n和a的gcd)
int s,t;
exEuclidean(n,a,s,t); //因为传引用,s和t得到解了
int a_ = (t >= 0) ? (t % n) : ((t-t*n)%n); //乘法逆就是t映射于n的值
int x0 = (b*a_)%n;
printf("特解是%d\n",x0);
//(3)得到所有的通解
printf("通解是 x0 + k * %d , 0 <= k < %d\n",n,gcd_a_n);
printf("所有的通解为:\n");
vector<int> ans;
for(int i = 0 ; i < gcd_a_n; i++){
ans.push_back(x0 + i * n);
printf("%d ",ans[i]);
}
printf("\n");
}
}
运行结果如下: