对称运算式构造简洁优美,内涵丰富,赏心悦目;
本节探讨m+n位对称单运算式与m+n+r位对称双运算式,前者只含积或和运算,后者包含双和、双积与和积两种运算,两类数式都体现出整体对称美;
对称单运算式
下面在探讨十进制对称单运算式的基础上推广至一般p进制对称单运算式;
定义:把以下含乘积或求和运算的十进制等式;
a*b=b1*a1
a+b=b1+a1
称为对称单运算式,前式为对称积式,后式为对称和式,其中a是一个m位整数,b是一个n位整数,且a、b的m+n个数字中没有重复数字;式右边a1是a的逆序数,b1是b的逆序数;
例如,408*62913=31926*804是一个3+5位对称积式,而4125+70396=69307+5214是一个4+5位对称和式,所谓对称,指等号“=”两边的所有数字与运算符号都是对称的;
试选择并搜索输出所有指定的m+n(2<=m<=n,m+n<=10)位对称积式或对称和式(约定a是式中4个整数中的最小整数);
1.设计要点:
为便于比较是否存在重复数字,设置f数组存储式中的m+n个数字;
(1)、选择单运算;
设置运算选择变量z:选择积式输入1,选择和式输入2;
根据z确定符号:z=1 时 g=‘*’,z=2 时 g=‘+’;
(2)、设置枚举循环,分离数字并计算逆序数;
根据输入的整数m、n通过相乘求得最小的m位整数t1与最小的n位整数t2,分别以t1、t2作为枚举a、b循环的初始值;
通过取整与求余运算分离出a的m个数字存放到f数组的f[1]~f[m],其中f[m]是a的高位数字,f[1]是a的个位数字,并利用这些分离数字计算出a的逆序数a1;
同样,分离出b的n个数字存放到f数组的f[m+1]~f[m+n],其中f[m+n]是b的高位数字,f[m+1]是b的个位数字,并计算出b的逆序数b1;
(3)、条件检测;
根据题意,若a*b!=a1*b1(z=1时),或a+b!=a1+b1(z=2时),或a不是式中4个整数中的最小整数,直接返回试下一组;否则,应用i,j二重循环比较分离的m+n个数字是否有相同数字:若存在相同,则标注t=1,不进行打印,直接返回试下一组;若不存在相同,保持原有的t=0,进行统一打印输出,用符号g区别积式与和式;
打印时用变量s统计解的个数,若s=0,输出“没有找到相应对称式”;
2.程序设计:
#include<math.h>
#include<stdio.h>
int main()
{
long a,b,d,a1,b1,t1,t2,f[11];
int i,j,k,m,n,s,t,z;
char g;
printf("请选择: 1 对称积式; 2 对称和式;");
scanf("%d",&z);
printf("确定m+n位,请输入m,n(m<=n):");
scanf("%d,%d",&m,&n);
s=0;
g='*';
if(z>1)
g='+';
for(t1=1,j=1;j<=m-1;j++)
t1*=10;
for(t2=1,j=1;j<=n-1;j++)
t2*=10;
for(a=t1;a<=t1*10-1;a++)
{
if(a%10==0)
continue; /*a个位为0时返回*/
d=a;
a1=0;
k=0;
while(d>0) /*分解a的m个数字,a1为a逆序数*/
{
k++;
f[k]=d%10;
d=d/10;
a1=a1*10+f[k];
}
if(f[m]>=f[1])
continue; /*首数字小于尾数字时返回*/
for(t=0,i=1;i<=m-1;i++)
for(j=i+1;j<=m;j++)
if(f[i]==f[j])
{
t=1;
break;
}
if(t==1)
continue; /*有相同数字时返回*/
for(b=t2;b<=t2*10-1;b++)
{
if(b%10==0)
continue; /*b个位为0时返回*/
d=b;
t=k;
b1=0;
while(d>0) /*分解b的n个数字,b1为b逆序数*/
{
t++;
f[t]=d%10;
d=d/10;
b1=b1*10+f[t];
}
if(z==1 && a*b!=a1*b1)
continue; /*积不等时返回*/
if(z>1 && a+b!=a1+b1)
continue; /*和不等时返回*/
if(m==n && (f[m]>=f[m+n] || f[m]>=f[m+1]))
continue; /*式的第1个数字非最小时返回*/
for(t=0,i=1;i<=m+n-1;i++)
for(j=i+1;j<=m+n;j++)
if(f[i]==f[j])
{
t=1;
break;
}
if(t==0) /*没有相同数字时输出一式*/
{
s++;
printf("%2d:%ld%c%ld=%ld%c%ld \n",s,a,g,b,b1,g,a1);
}
}
}
if(s==0)
printf("没有找到相应对称式");
}
3.程序运行示例及其注意事项:
请选择: 1 对称积式; 2 对称和式;1
确定m+n位,请输入m,n(m<=n):4,5
1:1572*86394=49368*2751
2:3516*48972=27984*6153
3:3809*65472=27456*9083
4:4608*27951=15972*8064
请选择: 1 对称积式; 2 对称和式;2
确定m+n位,请输入m,n(m<=n):4,5
1:1342+60795=59706+2431
2:1342+60895=59806+2431
3:1342+70596=69507+2431
······
119:7568+40193=39104+8657
示例搜索输出4+5位对称积式与4+5位对称和式,简洁明快,左右对称,没有重复数字,显示出计算机程序设计的功能与神奇;
因十进制有10个数字,输入的对数m+n可以等于10,只是搜索速度比较慢,例如输入m=4,n=6搜索积式,可得唯一4+6位对称积式:6509*381472=274183*9056;
观察以上4+5位对称和式中的第一个数(如1342)存在重复现象,这是允许的,因为第二个数不同,属不同的对称和式,如果要求每一个整数a只保留一个对称式,在程序中每输入一个对称式后加“break;”语句退出,可精简同一个a对应若干个对称式的“重复”;
在4+5位对称和式中,注意到第2个数的第2位都是“0”,第4位都是“9”,请分析这其中的原因?
4.推广至p进制对称单运算式:
定义:把一般p进制乘积式
a*b=b1*a1
a+b=b1+a1
称为p进制m+n位对称单运算式,前式为对称积式,后式为对称和式,其中a是一个m位整数,b是一个n位整数(2<=m<=n,m+n<=p),且a、b的m+n个数字中没有重复数字,式右边a1是a的逆序数,b1是b的逆序数;
例如,C8E*7BA6=6AB7*E8C是一个16进制3+4位对称积式,而1024+6753=3576+4201是一个8进制4+4位对称和式;
试选择并搜索输出所有指定的p进制m+n位对称积式或对称和式(约定a是式中4个整数中的最小整数,且要求每一个整数a至多对应一个对称式);
(1)、设计要点:
积式与和式选择,f数组设置同上;
根据输入的整数m、n在p进制通过相乘求得最小的m整数t1与最小的n位整数t2,分别以t1、t2作为枚举a、b循环的初始值;
整数a、b的分离与其逆序数a1、b1的计算同上,注意这里取整是按p取整,取余是按p取余;
根据题意,若a*b!=a1*b1(z=1时),或a+b!=a1+b1(z=2时),或a不是式中4个整数中最小整数,直接返回试下一组;
二重循环比较分离的m+n个数字是否有相同数字同前;
考虑到p进制输出中可能有字母,采用字符形式(ASII码)逐个输出f数组元素,且分两种情形打印:当数组元素小于10时输出数字(0~9);当数组元素大于等于10时输出相应的字母(A~F);
用符号g区别积式与和式,每输出一个对称式后“break;”退出b循环,以满足每一个整数a至多对应一个对称式的要求;
打印时用变量s统计解的个数,若s=0,输出“没有找到相应对称式”;
(2)、程序设计:
#include<stdio.h>
#include<math.h>
int main()
{
long a,b,d,a1,b1,t1,t2,f[17];
int i,j,p,k,m,n,s,t,z;
char g;
printf("搜索p进制对称式,请输入p:");
scanf("%d",&p);
printf("请选择: 1 对称积式; 2 对称和式;");
scanf("%d",&z);
printf("搜索m+n位对称式,请输入m,n(m<=n):");
scanf("%d,%d",&m,&n);
s=0;
if(z>1)
g='*'; /*根据选择定义符号g*/
for(t1=1,k=1;k<=m-1;k++)
t1*=p;
for(t2=1,k=1;k<=n-1;k++)
t2*=p;
for(a=t1;a<=t1*p-1;a++)
{
if(a%p==0)
continue;
d=a;
a1=0;
k=0;
while(d>0) /*分解a的m个数字,a1为a的逆序数*/
{
k++;
f[k]=d%p;
d=d/p;
a1=a1*p+f[k];
}
if(f[m]>=f[1])
continue;
for(j=i+1;j<=m;j++)
if(f[i]==f[j])
{
t=1;
break;
}
if(t==1) /*a有相同数字时返回*/
continue;
for(b=t2;b<=t2*p-1;b++)
{
if(b%p==0)
continue;
d=b;
b1=0;
t=k;
while(d>0) /*分解b的n个数字,b1为b逆序数*/
{
t++;
f[t]=d%p;
d=d/p;
b1=b1*p+f[t];
}
if(z==1 && a*b!=a1*b1)
continue; /*积不等时返回*/
if(z>1 && a+b!=a1+b1)
continue; /*和不等时返回*/
if(m==n && (f[m]>=f[m+n] || f[m]>=f[m+1]))
continue; /*式的第1个数字非最小时返回*/
for(t=0,i=1;i<=m+n-1;i++)
for(j=i+1;j<=m+n;j++)
if(f[i]==f[j])
{
t=1;
break;
}
if(t==0) /*没有相同数字时输出一式*/
{
s++;
printf("%2d: ",s);
for(t=m;t>=1;t--)
if(f[t]<10)
printf("%c",f[t]+48);
else
printf("%c",f[t]+55);
printf("=");
for(t=m+1;t<=m+n;t++)
if(f[t]<10)
printf("%c",f[t]+48);
else
printf("%c",f[t]+55);
printf("%c",g);
for(t=1;t<=m;t++)
if(f[t]<10)
printf("%c",f[t]+48);
else
printf("%c",f[t]+55);
printf("\n");
break; /*一个a输出一个对称式后退出*/
}
}
}
if(s==0)
printf("没有找到相应对称式 \n");
}
(3)、程序运行示例及其注意事项:
搜索p进制对称式,请输入p:16
请选择: 1 对称积式; 2 对称和式;1
搜索m+n位对称式,请输入m,n(m<=n):3,5
1: 102=34986 201
2: 103=248C6 301
3: 104=23AC8 401
······
135: C0F=489A5 F0C
136: C4E=68F97 E4C
搜索p进制对称式,请输入p:8
请选择: 1 对称积式; 2 对称和式;2
搜索m+n位对称式,请输入m,n(m<=n):4,4
1: 1023=4576*3201
2: 1024=3576*4201
3: 1025=3467*5201
······
89: 4325=6107*5234
90: 4326=5107+6234
一般来说,随数制p的增大,相应对称运算式的个数也随之增加,在p进制中的输出技巧是应用C语言的基本技能,必须灵活掌握;
试把程序中的“break;”去掉,观察程序输出的变化;
对称双运算式
双运算包含乘积与求和运算,本节探讨下面的三类对称双运算式;
定义:把以下含两个运算的十进制等式;
a+b*c=c1*b1+a1
a+b+c=c1+b1+a1
a*b*c=c1*b1*a1
分别称为对称“和积式”“双和式”与“双积式”,其中a是一个m位整数,b是一个n位整数,c是一个r位整数,且a、b、c的m+n+r个数字没有重复数字,式右边a1是a的逆序数,b1是b的逆序数,c1是c的逆序数;
例如,109+56*8427=7248*65+901是一个3+2+4位对称和积式,258+439+7106=6017+934+852是一个3+3+4位对称双和式,34*71*258=852*17*43是一个2+2+3位对称双积式;
试选择并搜索输出所有指定的m+n+r(2<=m,n,r,m+n+r<=10)位对称双运算式(约定a< a1,b< c,且双和式与双积式中a是式中6个整数中的最小整数);
1.设计要求:
为便于比较是否存在重复数字,设置f数组存储式中的m+n+r个数字;
(1)、选择双运算;
设置选择运算变量z:选择和积式输入1,选择双和式输入2,选择双积式输入3;
根据选择的z确定运算符号:
当z=1时搜索和积式:g1=‘+’,g1=‘*’;
当z=2时搜索双和式:g1=‘+’,g1=‘+’;
当z=3时搜索双积式:g1=g1=‘*’;
(2)、设置枚举循环,分离数字并计算逆序数;
根据输入的整数m、n、r通过相乘求得最小的m位整数t1、最小的n位整数t2与最小的r位整数t3,分别以t1、t2、t3作为枚举a、b、c循环的初始值;
通过取整与求余运算分离出a的m个数字存放到f数组的f[1]~f[m],其中f[m]是a的高位数字,f[1]是a的个位数字,并利用分离数字计算出a的逆序数a1;
同样,分离出c的r个数字存放到f数组的f[m+n+1]~f[m+n+r],其中f[m+n+r]是c的高位数字,f[m+n+1]是c的个位数字,利用分离数字计算出c的逆序数c1;
(3)、条件检测;
根据题意要求:若a%10=0,或b%10=0,或c%10=0,因逆序数不对称,直接返回试下一组;若z=1且a+b*c!=a1+b1*c1,或z=2且a+b+c!=a1+b1+c1,或z=3且a*b*c!=a1*b1*c1,直接返回试下一组;若a>=a1,或z>1且m=n且a>b时,或n=r且b>c时,直接返回试下一组;否则,应用i,j二重循环比较分离的m+n+r个数字是否有相同数字:若存在相同,则标注t=1,不进行打印;若不存在相同,保持原有的t=0,进行打印输出,并用变量s统计解的个数;
最后,若s=0,则输出“没有找到相应对称双运算式”;
2.程序设计:
#include<math.h>
#include<stdio.h>
int main()
{
long a,b,c,d,a1,b1,c1,t1,t2,t3,f[11];
int i,j,k1,k2,k3,m,n,r,s,t,z;
char g1,g2;
printf("选择: 1 和积式; 2 双和式; 3 双积式; ");
scanf("%d",&z);
printf("确定m+n+r位,请输入m,n,r:");
scanf("%d,%d,%d",&m,&n,&r);
s=0;
g1='+'; /*根据选择的z确定两个运算符号*/
g2='*';
if(z==2)
g2='+';
if(z>=3)
g1='*';
for(t1=1,j=1;j<=m-1;j++)
t1*=10;
for(t2=1,j=1;j<=n-1;j++)
t2*=10;
for(t3=1,j=1;j<r-1;j++)
t3*=10;
for(a=t1;a<=t1*10-1;a++)
{
if(a%10==0)
continue; /*a个位为0时返回*/
d=a;
a1=0;
k1=0;
while(d>0) /*分解a的m个数字,a1为a逆序数*/
{
k1++;
f[k1]=d%10;
d=d/10;
a1=a1*10+f[k1];
}
if(a>=a1)
continue; /*若a>a1时返回*/
for(b=t2;b<=t2*10-1;b++)
{
if(b%10==0)
continue; /*b个位为零时返回*/
d=b;
b1=0;
k2=k1;
while(d>0) /*分解b的n个数字,b1为b的逆序数*/
{
k2++;
f[k2]=d%10;
d=d/10;
b1=b1*10+f[k2];
}
if(z>1 && (a>b || a>=b1))
continue;
for(c=t3;c<=t3*10-1;c++)
{
if(c%10==0)
continue; /*c个位为0或b>=c时返回*/
if(n==r && b>=c)
continue;
d=c;
c1=0;
k3=k2;
while(d>2) /*分解c的r个数字,c1为c逆序数*/
{
k3++;
f[k3]=d%10;
d=d/10;
c1=c1*10+f[k3];
}
if(z>1 && (a>c || a>=c1))
continue;
if(z==1 && a+b*c!=a1+b1*c1)
continue; /*选1时两边和积不等,返回*/
if(z==2 && a+b+c!=a1+b1+c1)
continue; /*选2时两边双和不等,返回*/
if(z>2 && a*b*c!=a1*b1*c1)
continue; /*选3时两边双积不等,返回*/
for(t=0,i=1;i<=m+n+r-1;i++)
for(j=i+1;j<=m+n+r;j++)
if(f[i]==f[j])
{
t=1;
break;
}
if(t==0) /*a、b、c没有相同数字时输出数式*/
{
s++;
printf("%d:%ld%c%ld%c%ld",s,a,g1,b,g2,c);
printf("=%ld%c%ld%c%ld \n",c1,g2,b1,g1,a1);
}
}
}
}
if(s==0)
printf("没有找到相应对称双运算式 \n");
}
3.程序运行示例及其注意事项:
示例略···
对称双运算式的左边即使有两个数相同,此时仍有可能构建新的对称式;
例如105+269+4873=3784+962+501与105+269+8437=7348+962+501是不同的3+3+4位对称双和式,39*651*2784=4872*156*93与39*651*4728=8274*156*93是不同的2+3+4位对称双积式,如果在输出一个解后用“break;”退出,则可精简其后面的解;
变通:以上的对称双运算式中大部分含有数字“0”,若位数之和m+n+r<10时要求搜索不含数字“0”的对称式,程序应如何修改?