本节探讨一类具有 趣味填数特性的数式——优美数式 ,之所以称为优美,是因为数式中各数字不重复出现;
优美和式
试把1,2,……,9这9个数字分别填入以下和式的9个口中,为体现优美,要求1~9这9个数字在式中出现一次且只出现一次,使得和式成立:
- 口 口 口 + 口 口 口 = 口 口 口;
约定以上和式左边的前3位数小于后3位数,且右边的和数相同的为同一和式,即要求所有和式的右边和不同;
搜索并输出所有9数字优美和式;
1.设计要点:
这是一道容易发生增解与遗解的填数趣题,要求填入每个数式的9个数字为1,2,……,9,既不遗漏,也不重复;
为操作方便,设置m数组存储和式中的3个数,即:m(1)+m(2)=m(3);
为不至于重复,设m(1)< m(2);设置m(3),m(1)循环,m(3)为外循环,每打印输出一个解即跳出,保证一个m(3)至多输出一个解,不至于输出右边相同的和式;
为判别是否优美,即是否寸在重复数字,把m(1)、m(2)、m(3)分离数字,并用f数组统计每个数字的个数(f(k)即数字k的个数,k=0,1,……,9)成立,即得没有重复数字的和式,即为优美和式,输出并用n统计解的个数;
2.程序设计:
#include<stdio.h>
int main()
{
int n,x,y,t,k,m[4],f[11];
printf("9数字优美和式:\n");
n=0;
for(m[3]=379;m[3]<=987;m[3]++)
for(m[1]=123;m[1]<m[3]/2;m[1]++) /*对m(3),m(1)实施枚举*/
{
m[2]=m[3]-m[1];
for(k=0;k<=9;k++)
f[k]=0;
for(k=1;k<=3;k++)
{
y=m[k];
while(y>0); /*分离各数字用f数组统计*/
{
x=y%10;
f[x]=f[x]=f[x]+1;
y=y/10;
}
}
for(t=0,k=1;k<=9;k++)
if(f[k]!=1)
t=1; /*检验是否有重复数字*/
if(t==0) /*打印9数字优美和式*/
{
printf("%5d+%3d=%3d ",m[1],m[2],m[3]);
n++;
if(n%4==0)
printf("\n");
break; /*对一个和数输出后即退出*/
}
}
printf("\n共%d个\n",n);
}
3.程序运行示例及其注意事项:
9数字优美和式:
173+286=459 173+295=468 127+359=486 127+368=495
162+387=549 128+439=567 182+394=576 216+378=594
······
341+586=927 152+784=936 162+783=945 216+738=954
215+748=963 314+658=972 235+746=981
共31个
案例要求右边的和数相同的为同一和式,减少了重复,例如,当右边的和数为459时,由173+286=459,右边两数交换个位数字得176+283=459,交换十位数字183+276=459,这些交换造成的重复有损美感;
4.引申至10数字优美和式:
试把0,1,2,……,9这10个数字分别填人以下和式的10个口中,为体现优美,要求0~9这10个数字在式中出现一次且只出现一次,使得和式成立:
- 口 口 口 + 口 口 口 = 口 口 口 口;
约定以上和式中左边的前3位数小于后3位数,且右边的和数相同的为同一和式,即要求所有和式的右边和不同;
搜索并输出所有10数字优美和式;
(1)、设计要点:
为操作方便,设m(1)+m(2)=m(3),m(1)< m(2);
建立m(3)与m(1)循环:显然1023<=m(3)<1800,102<=m(1)< m(3)/2;
由和式知m(2)=m(3)-m(1);
优美判别同上;
(2)、程序设计:
#include<stdio.h>
int main()
{
int n,x,y,t,k,m[4],f[11];
printf("10数字优美和式:\n");
n=0;
for(m[3]=1023;m[3]<=1802;m[3]++)
for(m[1]=102;m[1]<m[3]/2;m[1]++) /*对m(3),m(1)实施枚举*/
{
m[2]=m[3]-m[1];
for(k=0;k<=9;k++)
f[k]=0;
for(k=1;k<=3;k++)
{
y=m[k];
while(y>0) /*分离各数字用f数组统计*/
{
x=y%10;
f[x]=f[x]+1;
y=y/10;
}
}
for(t=0,k=0;k<=9;k++)
if(f[k]!=1)
t=1; /*检验是否有重复数字*/
if(t==0) /*打印优美和式*/
{
printf("%5d+%3d=%4d ",m[1],m[2],m[3]);
n++;
if(n%4==0)
printf("\n");
break; /*对一个和数输出后即退出*/
}
}
printf("\n共%d个\n",n);
}
(3)、程序运行示例及其注意事项:
10数字优美和式:
437+589=1026 246+789=1035 264+789=1053 473+589=1062
324+765=1089 342+756=1098 347+859=1206 426+879=1305
624+879=1503 743+859=1602
共10个
以上两程序中的“break;”语句确保右边的和数相同只输出一个和式,请删除该语句后运行程序,会出现和数相同的多个和式,之所以约定“右边的和数相同的为同一和式”,就是起到一个精简作用;
优美综合式
本节设计构建一类优美综合数学式,这是一个有趣也有难度的填数游戏,数学式称为“优美”,是指各个数字在式中出现而不重复;数学式称为“综合”,是指该数学式中包含有加、减、乘、除与乘方运算;
1.案例提出:
把数字1,2,……,9这9个数字分别填入以下含加、减、乘、除与乘方(^,例2^3即为2^3)的综合运算式中的9个口中,使得该式成立:
- 口^口 + 口口 ÷ 口 - 口口口 × 口 = 0;
要求数字1,2,……,9这9个数字在式中出现一次且只出现一次,且约定数字“1”不能为一位数(即排除式中的各个1位数为1这一平凡情形);
2.按double型设计:
因式中出现乘方(a^b)运算,自然想到应用数据类型double进行设计;
(1)、设计要点:
设置f数组存储式中的9个数字,方便比较是否存在重复数字;
式中含有加、减、乘、除与乘方5种运算,应用枚举设计求解;
设式左的6个整数从左至右分别为a、b、z、c、d、e,即:
- a^b+z/c-d*e=0;
其中z为2位整数,d为3位数,a、b、c、e为大于1的一位整数;
设置a、b、c、d、e、z循环,其中设计z为c的倍数;
1)、若等式不成立,即pow(a,b)+z/c!=d*e,则返回继续;
2)、检测式中9个数字是否存在相同数字:对6个整数共9个数字进行分离,9个数字分别赋值给数组f[1]~f[9];连同附加的f[0]=0,共10个数字在二重循环中逐个比较:若存在相同数字,t=1,不作输出;若不存在相同,即式中9个数字为1~9不重复,保持标记t=0,则输出所得的优美综合运算式,并设置n统计解的个数;
(2)、程序设计:
#include<stdio.h>
#include<math.h>
int main()
{
double a,b,c,d,e,z;
int j,k,t,n,f[10];
printf("口^口 + 口口 ÷ 口 - 口口口 × 口 = 0\n");
n=0;
for(a=2;a<=9;a++)
for(b=2;b<=9;b++)
for(c=2;c<=9;c++)
for(z=2*c;z<=98;z=z+c) /*各数实施枚举,确保z为c的倍数*/
for(d=102;d<=987;d++)
for(e=2;e<=9;e++)
{
if(z<10 || pow(a,b)+z/c!=d*e)
continue; /*检验等式是否成立*/
t=0;
f[0]=0; /*9个数字赋给f数组*/
f[1]=a;
f[2]=b;
f[3]=c;
f[4]=e;
f[5]=floor(z/10);
f[6]=fmod(z,10);
f[7]=floor(d/100);
f[8]=fmod(d,10);
f[9]=floor(fmod(d,100)/10);
for(k=0;k<=8;k++)
if(f[k]==f[j]) /*检验数字是否有重复*/
{
t=1;
break;
}
if(t==0)
{
n++; /*输出一个解*/
printf("%2d:%.0f^%.0f+%.0f/%.0f",n,a,b,z,c);
printf("-%.0f*%.0f=0 \n",d,e);
}
}
}
(3)、程序运行示例及其注意事项:
口^口 + 口口 ÷ 口 - 口口口 × 口 = 0
1: 4^6+72/9-513*8=0
2: 5^4+78/6-319*2=0
以上所得两个数式中包含有加、减、乘、除与乘方5种运算,也包含0,1,2,……,9这10个数字,充分体现了数学式的形态优美与和谐美;
3.案例引申:
把以上综合运算式右边的“0”引申为一位参数f,即求解一下更一般的数学式:
- 口^口 + 口口 ÷ 口 - 口口口 × 口 = f;
设含乘方(a^b)、加、减、乘、除的综合运算式的右边为一位非负整数f,请把数字0,1,2,……,9这10个数字中不同与数字f的9个数字不重复填入式左边的9个口中(约定数字“1”“0”不出现在一位数中,且“0”不为整数首位),使得该运算式成立;
输入整数f(0<=f<=9),输出对应的综合运算式;
(1)、设计要点:
设置m数组存储式中除f之外的6个整数,g数组统计式中7个整数的10个数字的频数;
把所有变量简单设置为整型,其中乘方a^b用a自乘b次实现;
同样,设综合运算式为:
- a^b+z/c-d*e=f;
同样是枚举设计,这样处理,可省略z循环,同时省略z是否能被c整除,省略等式是否成立的检测;
计算z后,检测z是否为两位数,若计算所得z非两位数,则返回;
然后分别对7个整数进行数字分离,设置g数组对7个整数分离的共10个数字进行统计,g(x)即为数字x(0~9)的个数;
若某一g(x)不为1,不满足数字0,1,2,……,9这10个数字都出现一次且只出现一次,标记t=1;
若所有g(x)全为1,满足数字0,1,2,……,9这10个数字都出现一次且只出现一次,保持标记t=0,则输出所得的优美综合运算式;
(2)、程序设计:
#include<stdio.h>
#include<math.h>
int main()
{
int a,b,c,d,e,f,k,t,n,x,y,z,m[7],g[11];
n=0;
printf("请输入式右边的数字f:");
scanf("%d",&f);
for(a=2;a<=9;a++)
for(b=2;b<=9;b++)
for(c=2;c<=9;c++)
for(d=102;d<=987;d++) /*实施枚举*/
for(e=2;e<=9;e++)
{
for(t=1,k=1;k<=b;k++)
t=t*a; /*计算乘方a^b*/
z=(d*e+f-t)*c;
if(z<10 || z>98)
continue;
m[1]=a;
m[2]=b;
m[3]=c;
m[4]=d;
m[5]=e;
m[6]=z;
for(x=0;x<=9;x++)
g[x]=0;
g[f]=1;
for(k=1;k<=6;k++)
{
y=m[k];
while(y>0)
{
x=y%10;
g[x]++; /*分离数字给g数组统计*/
y=y/10;
}
}
for(t=0,x=0;x<=9;x++)
if(g[x]!=1) /*检验数字0~9各出现一次*/
{
t=1;
break;
}
if(t==0) /*输出一个解*/
{
n++;
printf("%2d: %d^%d+%d/%d",n,a,b,z,c);
printf("-%d*%d=%d \n",d,e,f);
}
}
if(n==0)
printf("无解! \n");
}
(3)、程序运行示例及其注意事项:
请输入式右边的数字f:6
1: 2^9+80/5-174*3=6
2: 5^4+18/9-207*3=6
3: 9^3+50/2-187*4=6
注意:以上设计中应用a自乘b次实现a^b,这样处理是简便的,同时,应用g数组进行数字统计来检验是否存在有重复数字,检测手段颇为新颖;
变通:把数字0,1,2,……,9这10个数字分别填入以下含加、减、乘、除与乘方的综合运算式中的10个口中(约定0、1不能为一位数,0不能为整数首位),请修改以上程序,使得下式成立:
- 口^口 + 口口 ÷ 口 - 口口口 × 口 = 口口;
请问:这一填数游戏共有多少种不同的填入法?