您的位置:首页 > 编程语言 > C语言/C++

桥本分数式

2017-01-06 18:02 1266 查看
日本数学家 桥本吉彦教授 于1993年10月在我国山东举行的中日美三国数学教育研讨会上向与会者提出以下填数趣题: 把1,2,……,9,这9个数字填入下式的9个方格中(数字不得重复),使下面的分数等式成立:

口/口口 + 口/口口 = 口/口口

桥本教授当即给出了一个解答,这一填数趣题的解是否唯一?如果不唯一究竟有多少个解?试求出所有解答(等式左边两边分数交换次序只算一个解答);

9数字分数式

1.说明:

采用回溯法逐步调整探求;

设置a数组,式中每一 口 位置用一个数组元素来表示,如下:

a(1)/a(2)a(3) + a(4)/a(5)a(6) = a(7)/a(8)a(9)

为避免解的重复,设a(1)< a(4),同时记式中的3个分母分别为:

m1 = a(2)a(3) = a(2)*10+a(3)

m2 = a(5)a(6) = a(5)*10+a(6)

m3 = a(8)a(9) = a(8)*10+a(9)

可见,问题的解空间是9位整数组,其约束条件是9位数中没有相同数字且必须满足分式的要求;

所求分数等式等价于整数等式 a(1)*m2*m3 + a(4)*m1*m3 = a(7)*m1*m2 成立,这一转化可以把分数的测试转化为整数测试;

为判断数字是否重复,设置中间变量g:先赋值g=1;若出现某两数字相同(即a(i)=a(k))或 a(1)>a(4),则赋值g=0(重复标记)

先从a(1)=1开始,逐步a(i)(1<=i<=9)赋值,每一个a(i)赋值从1开始递增至9,直至a(9)赋值,判断:

若i=9,g=1,a(1)*m2*m3 + a(4)*m1*m3 = a(7)*m1*m2同时满足,则为一组解,用n统计解的个数后格式输出这组解;

若i<9且g=1,表明还不到9个数字,则下一个a(i)从1开始赋值继续;

若a(9)=9,则返回前面一个数组元素a(8)增1赋值(此时,a(9)又从1开始)再试;

若a(8)=9,则返回前一个数组元素a(7)增1赋值再试,以此类推,直到a(1)=9时,以无法返回,意味着已全部试毕,求解结束;

2.程序设计:

#include<stdio.h>
int main()
{
int g,i,k,s,a[10];
long m1,m2,m3;
printf("桥本分数式有:\n");
i=1;
a[1]=1;
s=0;
while(1)
{
g=1;
for(k=i-1;k>=1;k--)
if(a[i]==a[k])
{
g=0;           /*两数相同,标记g=0*/
break;
}
if(i==9 && g==1 && a[1]<a[4])
{
m1=a[2]*10+a[3];
m2=a[5]*10+a[6];
m3=a[8]*10+a[9];
if(a[1]*m2*m3+a[4]*m1*m2==a[7]*m1*m2)
{
s++;
printf("(%2d)",s);
printf("%d/%d+%d/",a[1],m1,a[4]);
printf("%ld=%d/%ld  ",m2,a[7],m3);
if(s%2==0)
printf("\n");
}
}
if(i<9 && g==1)
{
i++;
a[i]=1;
continue;          /*不到9个数,往后继续*/
}
while(a[i]==9 && i>1)
i--;               /*往前回溯*/
if(a[i]==9 && i==1)
break;
else
a[i]++;            /*至第1个数为9结束*/
}
printf("共以上%d个解\n",s);
}


3.程序运行示例及其注意事项:

桥本分数式有:
( 1)1/26+5/78=4/39    ( 2)1/32+5/96=7/84
( 3)1/32+7/96=5/48    ( 4)1/78+4/39=6/52
( 5)1/96+7/48=5/32    ( 6)2/68+9/34=5/17
( 7)2/68+9/51=7/34    ( 8)4/56+7/98=3/21
( 9)5/26+9/78=4/13    (10)6/34+8/51=9/27
共以上10个解


注意:关于桥本分数式求解,已有应用程序设计得到9个解的报道,显然遗失了一个解,可见在程序设计求解时,如果程序中结构欠妥或参量设置不当,也可能造成解的遗失

如果要求分数式中各个分数均为最简分数,程序应如何修改?

引申10数字分数式

把0,1,2,……,9这10个数字填入下式的10个方格中,要求:

1)、各数字不得重复;

2)、数字“0”不得填在各分数的分子或分母的首位;

3)、式中各分数为最简真分数,即分子分母没有大于1的公因数;

口/口口 + 口/口口 = 口/口口


这一分数式填数究竟共有多少个解答?试应用回溯设计求出所有解答;

1.说明:

设置a数组表示式中的10个数字,即:

a(1)/a(2)a(3) + a(4)/a(5)a(6)a(7) = a(8)/a(9)a(10)

同时,记式中的3个分母分别为:

m1 = a(2)a(3) = a(2)*10+a(3);

m2 = a(5)a(6)a(7) = a(5)*100+a(6)*10+a(7);

m3 = a(9)a(10) = a(9)*10+a(10);

在上述回溯设计基础上修改若干参数:

数字从9个增加到10个,因而i<9改为i<10,i==9改为i=10;数组元素取值修改为从“0”开始,即a[1]=0,a[i]=0;数字“0”不得在各分数的分子与分母的首位,即“0”只能在a(3)、a(6)、a(7)与a(10)这4个数字中,因而在输出解的条件中增加a(3)*a(6)*a(7)*a(10)=0

此外,需要增加判断3个分数是否为真分数的测试循环;

2.程序设计:

#include<stdio.h>
int main()
{
int g,i,k,s,t,u,a[11];
long m1,m2,m3;
i=1;
a[1]=0;
s=0;
printf("10数字最简分数式:\n");
while(1)
{
g=1;
for(k=i-1;k>=1;k--)
if(a[i]==a[k])
{
g=0;           /*两数相同,标记g=0*/
break;
}
if(i==10 && g==1 && a[3]*a[6]*a[7]*a[10]==0)
{
m1=a[2]*10+a[3];
m2=a[5]*100+a[6]*10+a[7];
m3=a[9]*10+a[10];
if(a[1]*m2*m3+a[4]*m1*m3==a[8]*m1*m2) /*判断等式*/
{
t=0;
for(u=2;u<=9;u++)   /*测试3个分数是否为真分数*/
{
if(a[1]%u==0 && m1%u==0)
{
t=1;
break;
}
if(a[4]%u==0 && m2%u==0)
{
t=1;
break;
}
if(a[8]%u==0 && m3%u==0)
{
t=1;
break;
}
if(t==0)
{
printf("%d/%ld+%d/",a[1],m1,a[4]);
printf("%ld=%d/%ld\n",m2,a[8],m3);
}
}
}
if(i<10 && g==1)
{
i++;
a[i]=0;
continue;        /*不到10个数,往后继续*/
}
while(a[i]==9 && i>1)     /*往前回溯*/
i--;
if(a[i]==9 && i==1)
break;
else
a[i]++;          /*至第1个数为9结束*/
}
}
}


3.程序运行示例及其注意事项:

10数字最简分数式:
4/19+5/608=7/32


注意:以上10数字分数式求解是在9数字分数式设计的基础上变通所得,结构完全相同,请比较
a112
以上两个回溯设计的参数变化


如果把问题要求中的第3点去掉,即不要求各分数为最简真分数,程序应如果修改?
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息