将整数拆分为勾股数的问题解决
在群里看到这样一个问题:
解法如下:
1 #include <stdio.h> 2 3 #define MAX 500000 4 unsigned g_array[MAX + 1] = {0}; 5 6 #define EVEN(x) (((x)&1)==0) 7 #define ODD(x) (((x)&1)==1) 8 9 //判断两个数字是否互质的标准算法 10 unsigned __int64 gcd(unsigned __int64 a, unsigned __int64 b) /* Non-recursive version */ 11 { 12 unsigned __int64 ret=1; 13 unsigned __int64 t =0; 14 L: 15 if(a==b || b==0 ) return ret*a; 16 if( b==1 ) return ret; 17 if( a<b) { 18 t = a; 19 a = b; 20 b = t; 21 goto L; 22 } 23 24 if( EVEN(a) ) { 25 a >>= 1; 26 if( EVEN(b) ) { /* 2*gcd(a>>1, b>>1) */ 27 b >>= 1; 28 ret <<= 1; 29 } /* gcd(a>>1, b) */ 30 else {} 31 } 32 else { 33 if( ODD(b) ) { /* gcd( (a-b)/2, b) */ 34 a -= b; 35 a >>= 1; 36 } 37 else { /* gcd(a, b>>1) */ 38 b >>=1; 39 } 40 } 41 goto L; 42 } 43 44 //填充全局数组内容 45 void GetArray() 46 { 47 unsigned __int64 x; 48 unsigned __int64 y; 49 unsigned __int64 a; //直角边长度 50 unsigned __int64 b; //另一条直角边长度 51 unsigned __int64 c; //斜边长度 52 unsigned __int64 t; //三边总长度 53 54 for (x = 1; ; x += 1) 55 { 56 //令y的值为最小(为x+1),用勾股数公式求出三边长度 57 a = x * (x + 1) * 2; 58 b = (x + 1) * (x + 1) - x * x; 59 c = (x + 1) * (x + 1) + x * x; 60 61 //判断是否可以提前结束循环 62 if (a + b + c > MAX) 63 { 64 break; 65 } 66 67 //枚举y,总长度大于MAX时跳出循环 68 for (y = x + 1; y * (x + y) * 2 <= MAX; y += 1) 69 { 70 //用勾股数公式求出三边长度 71 a = y * x * 2; 72 b = y * y - x * x; 73 c = y * y + x * x; 74 75 //保证三边互质 76 if (gcd(gcd(a, b), c) == 1) 77 { 78 t = a + b + c; 79 80 //标识所有此总长度的倍数的地方拆分方案数加一 81 while (t <= MAX) 82 { 83 g_array[t] += 1; 84 t += (a + b + c); 85 } 86 } 87 } 88 } 89 } 90 91 int main() 92 { 93 //获取所有数字的解法数 94 GetArray(); 95 96 //求出其中解法数为一的个数 97 int nCount = 0; 98 for (int n = 0; n <= MAX; n += 1) 99 { 100 if (g_array[n] == 1) 101 { 102 nCount += 1; 103 } 104 } 105 106 printf("%d\n", nCount); 107 108 return 0; 109 }
答案是54446种