同基因数是由同一批数字通过不同排列所得的位数相同的整数,因此同基因数又称为排列数;
例如,由1、0、2、2这4个数字通过不同排列组成的4位整数1022、1202、1220、2012、2021、2102、2120、2201、2210是同基因数,而0122实际上只是一个3位数,并不含“0”,与上述诸数不同基因;
本节探索一类涉及同基因数的新颖数式——同基因和式;
由十进制同基因整数u、v、s组成的和式u+v=s称为同基因和式;
例如,1089+8019=9018是一个4位同基因和式,49896+49968=99864是一个5位同基因和式;
同时为了消除一个n位同基因和式中的3个数尾部同时加一个“0”后成为n+1位同基因和式的近亲衍生现象(例如10890+80190=91080),要求同基因和式u+v=s中u、v的个位数字不能同时为“0”;
对于给定的整数n(2<=n<=9),搜索并输出所有n位同基因和式u+v=s(约定u<=v);
1.设计要点:
为便于比较和式中的u、v、s是否同基因,设置数组f、g、h分别统计这3个整数中的数字频数;
(1)、枚举循环设置;
通过循环计算最小的n位整数t,然后设置n位加数u、v的枚举循环:
u:t~(10*t-1)/2(因v>=u,且s=u+v<10*t)
v:u~10*t-u-1(因s=u+v是n位数,即s<10*t)
当mod(u,10)=0 and mod(v,10)=0时,返回;
这样设计循环,可以确保u、v、s都是n位整数,且满足其中u、v的个位数字不同时为“0”,v>=u;
(2)、检测同基因;
对所得3个n位整数u、v、s(分别赋值给d1、d2、d3,以保证分解数字时u、v、s不变),通过n次循环分离其n个数字c,并分别用数组f、g、h统计数字c的频数;
在j(0~9)循环中比较3数组的值,若f[j]!=g[j]或f[j]!=h[j],说明3个整数u、v、s中至少有一个数字不同,非同基因,返回;
若所检测的3个整数u、v、s是同基因,则输出一个n位同基因和式u+v=s,用w统计个数;
2.程序设计:
#include
int main()
{
int b,c,j,k,n,w,f[10],g[10],h[10];
long d1,d2,d3,t,u,v,s;
printf("请输入位数:");
scanf("%d",&n);
w=0;
for(t=1,k=1;k<=n-1;k++)
t=t*10; /*计算最小的n位整数t*/
for(u=t;u<=(10*t-1)/2;u++) /*枚举n位加数u、v*/
for(v=u;v<=10*t-1-u;v++)
{
if(u%10==0 && v%10==0)
continue; /*消除近亲衍生现象*/
s=u+v;
d1=u;
d2=v;
d3=s;
b=0;
for(j=0;j<=9;j++)
f[j]=g[j]=h[j]=0;
for(j=1;j<=n;j++)
{
c=d1%10;f[c]++;d1=d1/10;
c=d2%10;g[c]++;d2=d2/10;
c=d3%10;h[c]++;d3=d3/10;
}
for(j=0;j<=9;j++)
if(f[j]!=g[j] || f[j]!=h[j])
{
b=1;
break; /*检验u、v、s是否同基因*/
}
if(b==0)
{
w++;
printf("%3d: %ld+%ld=%ld \n",w,u,v,s);
}
}
printf("共有%d个%d位同基因和式\n",w,n);
}
3.程序运行示例及其注意事项:
请输入位数:4
1: 1089+8019=9108
2: 1089+8091=9180
3: 1269+1692=2961
······
23: 4896+4968=9864
24: 4959+4995=9954
共有24个4位同基因和式
事实上,同基因和式可以突破“整数”的限制,即在同基因和式的u、v、s的相同位置加“小数点”后仍是同基因和式;
例如459.9+499.5=995.4 、49.59+49.95=99.54等显然为同基因和式;
程序的枚举搜索时间复杂度为10^2n,当n比较大时(如n>=6),搜索比较困难,降低算法的复杂度是一个艰难而有现实意义的课题;
4.p进制同基因和式:
下面拓广到一般p进制,试图在指定的p进制中搜索同基因和式;
由3个p(2<=p<=16)进制同基因整数u、v、s组成的和式u+v=s称为p进制同基因和式;
例如,1142+1214=2411是一个4位5进制同基因和式,14315+35114=51431是一个5位8进制同基因和式;
同时要求p进制同基因和式u+v=s中u、v的个位数字不能同时为“0”,以消除近亲衍生现象;
对于给定的正整数p(2<=p<=16)与位数n,搜索并输出所有n位p进制同基因和式u+v=s(约定u<=v);
(3)、设计要点;
1)、设置4个数组;
字符型d数组存储p进制的字符可能的字符“0123456789ABCDEF”;
一维f、g、h数组统计u、v、s的各个数字的频数,以便比较是否同基因;当检测为同基因和式后,f、g、h数组记录u、v、s从个位开始的各个数字,以便借d数组输出;
2)、枚举循环设置;
通过循环计算最小的n位p进制整数t,然后设置n位加数u、v的枚举循环:
u:t~(p*t-1)/2(因v>=u,且s=u+v< p*t);
v:u~p*t-u-1(因s=u+v是n位数,即s< p*t);
当mod(u,p)=0 and mod(v,p)=0时,返回;
这样设计循环,确保u、v、s都是p进制n位整数,且满足其中u、v的个位数字不同时为“0”,v>=u;
3)、检测同基因
对所得3个p进制n位整数u、v、s(分别赋值给d1、d2、d3,以保证分解数字时u、v、s不变),在n次循环中通过除p取余分离其n个数字c,并分别用一维数组f、g、h统计数字c的频数,例如,若f[3]=2,即数字“3”有2个;
在j(0~p-1)循环中比较3数组的值,若f[j]!=g[j]或f[j]!=h[j],说明3个整数u、v、s中至少有一个数字不同,即非同基因,返回;
4)、输出p进制和式;
当检测同基因和式成立后,改变用f、g、h数组记录u、v、s的从个位开始的各个数字,例如,若f[3]=2,即u中从个位开始的第3个数字为2;
设置3个从高位j=n-1到低位j=0的循环,则借助字符数组d输出d输出p进制数u、v、s,连接成一个p进制n位同基因和式u+v=s,用w统计其个数;
(2)、程序设计:
#include
int main()
{
int b,c,j,k,n,p,w,f[16],g[16],h[16];
long d1,d2,d3,t,u,v,s;
char d[]="0123456789ABCDEF";
printf("确定p进制,请输入p:");
scanf("%d",&p);
printf("请确定位数n:");
scanf("%d",&n);
w=0;
for(t=1,k=1;k<=n-1;k++)
t*=p; /*计算最小的n位p进制整数t*/
for(u=t;u<=(p*t-1)/2;u++)
for(v=u;v<=p*t-u-1;v++) /*枚举近亲衍生现象*/
{
if(u%p==0 && v%p==0)
continue; /*消除近亲衍生现象*/
s=u+v;
b=0;
d1=u;
d2=v;
d3=s;
for(j=0;j<=p-1;j++)
f[j]=g[j]=h[j]=0;
for(j=0;j<=n-1;j++) /*分离并统计u、v、s的p进制各数字*/
{
c=d1%p;f[c]++;d1=d1/p;
c=d2%p;g[c]++;d2=d2/p;
c=d3%p;h[c]++;d3=d3/p;
}
for(j=0;j<=p-1;j++) /*检验u、v、s是否同基因*/
if(f[j]!=g[j] || f[j]!=h[j])
{
b=1;
break;
}
if(b==0)
{
d1=u;d2=v;d3=s;
for(j=0;j<=n-1;j++) /*分离并记录u、v、s的p进制各数字*/
{
c=d1%p;f[c]++;d1=d1/p;
c=d2%p;g[c]++;d2=d2/p;
c=d3%p;h[c]++;d3=d3/p;
}
w++;
printf("%d: ",w);
for(j=n-1;j>=0;j--) /*借助d数组输出同基因和式u+v=s*/
printf("%c",d[f[j]]);
printf("+");
for(j=n-1;j>=0;j--)
printf("%c",d[g[j]]);
printf("=");
for(j=n-1;j>=0;j--)
printf("%c",d[h[j]]);
printf("\n");
}
}
printf("共有%d个%d进制%d位同基因和式 \n",w,p,n);
}
(3)、程序运行示例及其注意事项:
确定p进制,请输入p:16
请确定位数n:3
1: 200+200=200
2: 200+200=200
3: 000+000=000
4: 000+000=000
共有4个16进制3位同基因和式
设置数组f、g、h前后二用是本程序的一个特点;
以上所得16进制和式“78F+7F8=F87”简洁而优美,单纯靠想象是很难奏效的,程序设计可以发现与揭示出许多的神奇与美;
程序的时间复杂度高达p^2n,当n比较大时,运行时间比较长;
例如,搜索“7F8F+7FF8=FF87”等34个16进制4位同基因和式时花费数分钟,降低同基因和式算法的时间复杂度是非常必要的;