由微信群中的一道小问题引发的同余方程计算机解法

最近微信中有人发一个问题:
一筐鸡蛋:
1个1个拿,正好拿完。
2个2个拿,还剩1个。
3个3个拿,正好拿完。
4个4个拿,还剩1个。
5个5个拿,还剩4个。
6个6个拿,还剩3个。
7个7个拿,正好拿完。          
8个8个拿,还剩1个。          
9个9个拿,正好拿完。
问筐里有多少鸡蛋?
能算出这道题的智商不一般。
这个在数论中是属于解同余方程组,最经典的解法是使用孙子定理,但孙子定理有一个局限性,就是要求各个模数都互质,本题显然不满足这个特性。
先将本题的同余方程组列出来(第一个方程可以忽略不计):
x≡1 (mod 2)
x≡0 (mod 3)
x≡1 (mod 4)
x≡4 (mod 5)
x≡3 (mod 6)
x≡0 (mod 7)
x≡1 (mod 8)
x≡0 (mod 9)


手工解这个同余方程组会比较费劲,我们可以设计一个算法,用计算机来解题。


我们用计算机解题,可以先将两个方程合并成一个等价方程的做法,逐步将方程数止减少,最后得到同余方程的解。合并的思路是:

第一步:找到一个数y,使得

x≡a1(modm1) 等价于 x≡y (mod m1)

x≡a2(modm2)等价于 x≡y (mod m2)

即将2个方程转换为模数不变,余数相等的方程。

第二步:

合并这两个方程,它们的解方程就是x ≡y (mod M) M为m1,m2的最小公倍数。


不断执行上面的操作,将第一、第二个方程的解方程与第三个方程合并等到新的解方程,依此类推....,最后得到整个方程组的解。

解的存在性:


同余方程组

x≡a1(modm1)

x≡a2(modm2)

……

x≡an(modmn) 有解的充要条件是(mi,mj)|(ai-aj) (i,j=1,2,…,n) (i≠j)


由于我们每次只需要求解2个方程,不需要考虑n种情况,所以我们判断解是否存在的时候,只要判断2个方程即可。


下面是程序:


#include <iostream>
using namespace std;




struct squal{
int r;
int m;
};
bool bcansolve=true;
int gcd(int a,int b)//辗转相除求最大公约数
{
int c;
c=a%b;
while(c!=0)
{a=b;b=c;c=a%b;}
return (b);
}
squal mergesqual(squal a,squal b){
//方程化简
a.r %= a.m;
b.r %= b.m;
//判断是否有解
int sss=0;
sss =gcd(a.m,b.m);
if ( (a.r - b.r) % sss !=0)
{
bcansolve = false;
return a;
}
while(a.r%b.m != b.r){
a.r += a.m;
};
a.m = a.m * b.m /sss;//两个模数的最小公倍数做新的模数
return a;
}
int main(){
int n=0;
cout<<"输入方程个数";
cin>>n;
squal sa,sb;
cout<<"依次输入各个方程(格式:余数在前,模数在后,例如x≡2(mod 3),只需要输入2 3,再回车,一行一个):";
cin>>sa.r>>sa.m;
for (int i=0;i<n-1;i++)
{
cin>>sb.r>>sb.m;
sa = mergesqual(sa,sb);
}
sa.r %= sa.m;
cout<<endl;
if (!bcansolve)
{
cout<<"此方程组无解"<<endl;
}else{
cout <<"结果是:";
cout<<sa.r<<endl;
cout <<"模数是:";
cout<<sa.m<<endl;
}
system("pause");
return 0;

}

运行结果:



参考文献:

http://wenku.baidu.com/link?url=EqbrGzZdAh0j3WyjQWvaU2Brsv9VmnIbp7beSCmVfl6z8hp3dAesBRhiPA5O67-ag54g7wtoHa5C1xcSTRhSCmbCVgW0IQxHbBYniavqPHy

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值