对称运算式

对称运算式构造简洁优美,内涵丰富,赏心悦目;

本节探讨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”的对称式,程序应如何修改?

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值