加载中…
个人资料
  • 博客等级:
  • 博客积分:
  • 博客访问:
  • 关注人气:
  • 获赠金笔:0支
  • 赠出金笔:0支
  • 荣誉徽章:
正文 字体大小:

关于二次同余问题(Quadratic Equation)的解法

(2011-04-03 19:46:13)
标签:

算法

二次同余

quadratic

equation

it

分类: 计算机与 Internet
dreamboat的算法作业出了一道二次同余的问题,算法还真不好写,主要是模合数的情况有点麻烦,下面是我根据网上参考资料总结出的算法:

一、问题阐述:

         对形如:ax^2+bx+c = 0 (mod p) (A)

         x, a, b, c, p皆为整数,求出所有可能的解x

        

         问题可抽象为:

         输入: int a, b, c ,p

         输出: int x 使其满足方程(A)

 

二、算法思想:

         为简化问题,可先认为p为素数,且0<=a,b,c,x<p

         a=0时,(A)问题可转化为如 ax+b = 0 (mod p)(B)

         a!=0时,可使用配方法将(A)问题转化为求U^2+D = 0 (mod p)(C)的解,具体为:

1)       p=2,由于x<p,故x只能取01;若c=0,则显然x=0是其中一个解,否则x=0不是问题的解;当a+b+c mod p0x=1为问题的解,否则x=1不是问题的解。

2)       p为奇素数时,若a(p-1)/2≡1 (mod p)不成立则原问题无解。否则一律将(A)转变为(C),其中U=2Ax+B D=(4AC-B2)。解问题(C)可采用Shank-Tonelli算法,当解出一个U时,在[0,p-1]范围内p-U为问题(C)的另外一个解,因此原问题也对应着两个解,当然存在这两个解相同的情况。剩下的步骤将U代入(B)求解x

3)       求解(B)使用Extended Euclid算法

 

Shank-Tonelli算法[1]如下:

1)       k, 使得p-1 = 2nk

2)       求出能满足q(p-1)/2≡ -1 (mod p)最小的q

3)       t = a(k+1)/2 % p and let r = ak%p

4)       t为问题的一个解,如果能满足r≡1 (mod p) ,否则转5)

5)       求出最小的i使得满足r2i≡1(mod p)

6)       分别计算e = 2(n-i-1) u = q(ke)%P t = (t*u)%P r = (r*u*u)%P

7)       转到4

 

p为合数时,不能直接使用上面的解法。由孙子定理[3]可知(A)的解为将p分解成如p1k1p2k2…pnkn时对应各子同余式在扩展解空间情况下的公共解,其中p1p2…pn为素数。

如:x^2 mod 6 = 0 解为24。而X^2 mod 2 = 0 解为0,X^2 mod 3 = 0 解为12,扩展解空间时,x+kp均为原问题的解,因此在[0,6]范围内,X^2 mod 2 = 0解为024X^2 mod 3 = 0解为1245,因此其公共解为24

故此时(A)问题转化为求ax^2+bx+c = 0 (mod p^k)(D)的解,求此类问题可使用Hensel's_lemma[2],在此就不列出其算法。

因此当p为合数时算法步骤为

1)       p分解为p1k1p2k2…pnkn

2)       针对每个pi,使用Hensel’s lemma求出(D)的解

3)       在扩展解空间后求出所有pi的公共解

 

三、算法代码(p为素数部分)

 

         Input: a, b, c, p

         Output: {X}

         procedure solve_all_problem (a, b, c, p)

                   if a== 0

                            if b==0&&c!=0

                                     return 0; // [0,p-1] 0 是唯一的解

                            else if(b!=0){

                                     int result = solve_linear(b,-c,p); //利用Extended Euclid算法解线性方程

                                     return result;

                            else

                                     return NO_SOLUTION;

                            end if

         else if p == 2

                   int solution_a = -1,solution_b = -1; //初始化为无解

                   if (c%2) == 0

                     solution_a = 0;

                   end if

                   if (a + b + c)%p == 0

                     solution_b = 1;

                   return solution_a and solution_b //两个可能的解

                   end if       

         else

                   int u;

                   int d = ((long long)b*b-4LL*a*c)%p;

                   u = shank_tonelli(d,p);

                   if u==-1

                            return NO_SOLUTION

                   else

                            int solution_a = solve_linear(2*a,u-b,p);

                            int solution_b = solve_linear(2*a,p-u-b,p);

                            if(solution_a==solution_b){

                                     return solution_a //只有一个解

                            else

                                     return solution_a and solution_b

                            end if                 

                   end if

         end if

        

四、测试用例:

input:2 3 4 6

output: 2 2 4

-------------------

input:4 3 3 13

output: 1 11

-------------------

input:17 8 1 71

output: 0

-------------------

input:2 3 5 7

output: 2 5 4

-------------------

input:0 4 0 7

output: 1 0

-------------------

input:2 34 9 19

output: 2 6 15

-------------------

input:12 5 27 2

output: 1 1

-------------------

input:1 179344794 146367396 179424691

output: 2 1876 78021

 

 

五、参考文献

[1] Tutorial for Quadratic Equations:

 http://www.codechef.com/wiki/tutorial-quadratic-equations

[2] Hensel’s Lemma: http://en.wikipedia.org/wiki/Hensel's_lemma

[3] 孙子定理: http://baike.baidu.com/view/157384.htm

0

阅读 收藏 喜欢 打印举报/Report
  

新浪BLOG意见反馈留言板 欢迎批评指正

新浪简介 | About Sina | 广告服务 | 联系我们 | 招聘信息 | 网站律师 | SINA English | 产品答疑

新浪公司 版权所有