先看看题目
思路
这是信息安全数学基础中一道初等数论的题目,也是em…我的作业。
这题我们拿到手上,由于数字太大,如果不借助计算机的话,只能用辗转相除法了。
将式子转化为ax+by=c的形式,便是499999x - 1533331y = 1
1. 辗转相除法:
这张图可能看起来有些抽象,不过用一个简单的例子来举例:
对于 3x + 7y = 2
对 3 和 7 进行辗转相除
7 = 3 * 2 + 1
这里余数为1,就不用算了
这里由于3和7的最大公因数是1
所以 1 = 7 - 3 * 2 ,所以 2 = 7 * 2 - 3 * 4
那么x 就是 - 4 , y 就是 2 咯。
显然对于499999x - 1533331y = 1来说,辗转相除要写相当多的式子,既然是作业,不如编程来解决。
2. 遍历找答案
回归正题,说道解二元一次不定方程,最最简单的思路当然是一个个试答案,比如499999x - 1533331y = 1,循环嵌套下一个个试,利用完全剩余系的知识,x可以有0-1533331取值,y那么就是0-499999个取值,总共也就1533331*499999这么多次验算,不过这属实有点逆天。
解题
也许计算机更擅长mod运算,毕竟有%
嘛
我们这道题给他化为同余方程不就行啦!
看看:499999x - 1533331y = 1
转化后:499999x ≡ 1 (mod 1533331)
我就只需要计算一个x啦,将x遍历1533331的完全剩余系即可,即0-1533331,只需要一个循环就能解决。
解二元一次方程的C语言程序
然后,我把这个更加普及了一下,(可能是我觉得解二元一次方程更广泛?)本来二元化一元就是一种不错的想法吧。
#include<stdio.h>
int main()
{
long long a,b,c;
long long x,y;
printf("二元一次不定方程ax+by=c特解求解\n");
printf("请输入a,b,c\n");
scanf("%lld%lld%lld",&a,&b,&c);
for(x=0;x<b;x++)
{
if((a*x)%b==(c%b)) //验证同余方程式,c%b而不是c这里需要mod个b
{
printf("X0=%lld\n",x);
printf("Y0=%lld",(c-a*x)/b);
break;
}
}
return 0;
}
嗯,那么499999x - 1533331y = 1的解也就是:
答案也就是418877
这里输入的a,b均为正数,毕竟模一个负数就相当于mod绝对值啦,但是我这里就没做什么处理,像这里我输入的是1533331是个正数,正常来讲把Y0变成正值就是方程的特解啦。
还有,由于程序的不完善,这里其实要求a,b,c均是正值,如果原式a和b取负值,改变x和y的正负就OK了,c的话就x和y都取相反数。