如果长方体的棱长x、y、z和体对角线长w都是正整数,就把它们叫做一组长方体数;
显然,长方体数是勾股数的推广;
试求指定区间 [a,b] (1<=a< b<10000)内的长方体数组(x,y,z,w)
探求长方体数
1.说明:
所求长方体数组 [a,b] 内的正整数x、y、z、w满足:
x²+y²+z²=w²
其中a<=x<=y<=z<=w<=b,这是一个涉及4个变量x、y、z、w的二次不定方程;
为了尽可能减少无效循环,根据 a<=x<=y<=z<=w<=b 的约定设置合适的循环参量是必要的;
注意到x²<=b²/3,且根据 x<=y<=z :
设置 x: a~sqrt(b*b/3);
设置 y: x~sqrt((b*b-x*x)/2);
设置 z: y~sqrt(b*b-x*x-y*y);
据以上x、y、z的取值直接计算w:若存在整数w满足 x*x+y*y+z*z=w*w,则找出一组满足条件式的整数x、y、z、w;
若输入的区间 [a,b] 范围比较小,可能不存在长方体数,为了避免此时输出出错,设置统计解的变量 k :
若 k=0,此时无解,则作必要的无解说明。
2.程序设计:
#include<stdio.h>
#include<math.h>
int main()
{
long a,b,d,k,x,y,z,w;
printf("请输入区间[a,b]的上下限a,b:");
scanf("%ld,%ld",&a,&b);
k=0;
for(x=a;x<=sqrt(b*b/3);x++) /*设置枚举三重循环*/
for(y=x;y<=sqrt((b*b-x*x)/2);y++)
for(z=y;z<=sqrt(b*b-x*x-y*y);z++)
{
d=x*x+y*y+z*z;
w=(int)sqrt(d); /*w为x、y、z的平方和开方*/
if(w>b)
break;
if(w*w==d)
{
k++;
printf("%3d: %ld,%ld,%ld,%ld\n",k,x,y,z,w);
}
}
if(k>0)
printf("在指定区间[%ld,%ld]中共有以上%ld组长方体数。\n",a,b,k);
else
printf("在指定范围内没有长方体数!\n");
}
3.程序运行示例及其注意事项:
请输入区间[a,b]的上下限a,b:100,200
1: 101,102,126,191
2: 102,102,119,187
3: 102,111,114,189
4: 102,120,120,198
5: 104,106,112,186
6: 104,107,116,189
7: 108,108,126,198
8: 108,116,117,197
在指定区间[100,200]中共有以上8组长方体数。
注意:以上输出表明,长方体数中x、y可能相等,y、z也可能相等。因此,在设置枚举循环时如果循环初值 y=x+1 开始,或者循环初值 z=y+1 开始,可能造成漏解。
六个正整数问题
加德纳(M.Gardner)是美国著名的科普专栏作家,他在1970年的《科学美国人》杂志上提出这个一般问题:
在一个长方体中,从一顶点出发的三条棱长、三个面的对角线长以及体对角线这七条线段中,能否同时出现六个正整数?
实际上,它是以下三个不同问题的综合形式:
*(1)、体对角线长是无理数,其余六条线段长是正整数;
*(2)、一条棱长是无理数,其余是正整数;
*(3)、一个面的对角线长是无理数,其余是正整数;
关于问题(1):
早在1719年, 哈克尔(P.Halcke) 已经发现,若长方体的棱长为117、44、240,则其面对角线的长度都是正整数(分别为267、244、125);
关于问题(2):
例如,取长方体的棱长为 a=124,b=957,c*c=13852800,那么各个面对角线的长度是965、3724、3843,体对角线的长度是3845。出去c是无理数之外,其余六个数都是正整数;
关于问题(3):
瑞士数学家 欧拉(L.Euler) 已经得到过该问题的一些解。其中一个的棱长是(104、153、672),另一个棱长是(117、520、756)。前者的体对角线是697,2个面对角线长是185、680,另外一个面对角线长为无理数;后者的体对角线长是925,2个面对角线长是533、765,另外一个面对角线长为无理数;
下面通过程序设计探讨指定区间上的问题(1):
在指定区间 [a,b] 内搜寻6个整数,其中三个整数是长方体的长、宽、高,另3个整数是该长方体的6个面的对角线长。
1.说明:
设长方体的 长、宽、高 分别为 x、y、z(x< y< z)(且最多存在两棱长相等),相对应面的对角线长分别为e1、e2、e3;
要使其各面对角线长e1、e2、e3都是整数,则x、y、z这三个数中每两个的平方和都应是平方数d1、d2、d3,也就是说,x、y、z中每两个都应是一组勾股数组的勾股数;
设置x、y、z三重循环:
注意到 x²< b²/2,且根据 x< y< z :
设置x: a~sqrt(b*b/2);
设置y: x+1~sqrt(b*b-x*x);
设置z: y+1~sqrt(b*b-x*x);
计算x、y的平方和赋给d1,d1再开方取整数赋给e1,即 d1=x* x+y* y ,e1=(int)sqrt(d1),若 d1=e1*e1,说明x、y为边长的面的对角线长e1为整数;
同样,判别以x、z为边长与以y、z为边长的面的对角线长是否为整数,当这三个判别同时满足时,输出一组“6个整数”的解;
2.程序设计:
#include<stdio.h>
#include<math.h>
int main()
{
long a,b,x,y,z,e1,e2,e3,d1,d2,d3,n=0;
printf("请输入区间[a,b]的上下限a,b:");
scanf("%ld,%ld",&a,&b);
for(x=a;x<sqrt(b*b/2);x++)
{
for(y=x+1;y<=sqrt(b*b-x*x);y++)
{
d1=x*x+y*y;
e1=(long)sqrt(d1);
if(d1==e1*e1&&e1<b)
{
for(z=y+1;z<=sqrt(b*b-x*x);z++)
{
d2=x*x+z*z;
e2=(long)sqrt(d2);
d3=z*z+y*y;
e3=(long)sqrt(d3);
if(d2==e2*e2&&d3==e3*e3&&e2<b&e3<=b)
{
n++;
printf("NO%ld:",n);
printf("%ld,%ld,%ld\n",x,y,z);
printf("各面对角线长:");
printf(" L1(%ld,%ld)=%ld",x,y,e1);
printf(" L2(%ld,%ld)=%ld",x,z,e2);
printf(" L3(%ld,%ld)=%ld\n",y,z,e3);
break;
}
}
}
}
}
}
3.程序运行示例及其注意事项:
请输入区间[a,b]的上下限a,b:1000,2000
NO1:1008,1100,1155
各面对角线长: L1(1008,1100)=1492 L2(1008,1155)=1533 L3(1100,1155)=1595
NO2:1200,1260,1375
各面对角线长: L1(1200,1260)=1740 L2(1200,1375)=1825 L3(1260,1375)=1865
完美长方体
如果有一个长方体,它的所有棱长、所有面对角线长和体对角线长都是正整数,则称它为完美长方体(Perfect Cuboid)
是否存在完美长方体?这是个著名的难题,至今还不知道答案。
一个非常自然的想法是,在”六个正整数“解答的基础上继续探索;
现有的探索结果还是两手空空,无法断言是否存在完美长方体。