逐位整除数是一类新颖有趣的整数;
定义n位逐位整除数:从高位开始,高1位能被1整除(显然),高2位能被2整除,……,以此类推,整个n位数能被n整除;
例如1024569就是一个7位逐位整除数,因为1024569能被7整除,高6位即102456能被6整除,高5位即10245能被5整除,……;
对指定的正整数n,搜索共有多少个不同的n位逐位整除数?存在n位逐位整除数的整数n是否有最大值?
试探索指定的n位逐位整除数,输出所有n位逐位整除数;
1.说明:
设置a数组,存放求解的逐位整除数的各位,a[1]存储最高位数字,a[2]存储次高位数字,……,a[n]存储n位数的个位数字;
在a数组中,数组元素a[1]为最高位,从1开始取值,显然能被1整除;a[2]从0开始取值,存放第2位数,前2位即a[1]*10+a[2]能被2整除;……
为了判别已取的 i 位数能否被i整除,设置 j 循环:
for(r=0,j=1;j<=1;j++)
{
r=r*10+a[j];
r=r%i;
}
1)、若r=0,即该i位数能被i整除,取标志量t=0,此时有两个选择:
2)、若r!=0,即前i位数不能被i整除,取标志量t=1,此时a[i]=a[i]+1,即第i位增1后继续;
若增值至a[i]>9,则a[i]=0即该位清零后i=i-1迭代回溯到前一位,直到第1位增值超过9后退出循环结束;
该算法可探索并输出所有n位逐位整除数,用s统计解的个数,若s=0,说明没有找到n位逐位整除数,输出“无解”;
2.程序设计:
#include
int main()
{
int i,j,n,r,t,s,a[100];
printf("逐位整除数n位,请确定n:");
scanf("%d",&n);
printf("所求%d位逐位整除数:\n",n);
for(j=1;j<=100;j++)
a[j]=0;
t=0;s=0;
i=1;a[1]=1;
while(a[1]<=9)
{
if(t==0&&i9&&i>1)
{ /*回溯*/
a[i]=0;
i--;
a[i]=a[i]+1;
}
}
else
t==0; /*余数r=0时,t=0*/
if(t==0&&i==n)
{
s++;
printf(" %d:",s);
for(j=1;j<=n;j++)
printf("%d",a[j]);
printf("\n");
a[i]=a[i]+1;
}
}
if(s==0)
printf("没有找到!\n");
else
printf("共以上%d个解。\n",s);
}
3.程序运行示例及其注意事项:
逐位整除数n位,请确定n:25
所求25位逐位整除数:
1:3608528850368400786036725
注意:输入n>25时,无解。这说明逐位整除数位数的最大值为25;
之所以说逐位整除数位数的最大值为25,是因为在这唯一的25位逐位整除数后添加0~9中任何一个数字后变为26位整数都不能被26整除。也就是说,不存在26位(及其以上)逐位整除数;
请验证以上求得的25位逐位整除数是否满足逐位整除数的整数特性:数的高k位能被k整除,k=1,2,……,25;
根据逐位整除数的递推特性,也可以应用递推设计来求解逐位整除数;
1.说明:
注意到逐位整除数的构造特点:n位逐位整除数的高n-1位是一个n-1位逐位整除数。因而可在每一个n-1位逐位整除数后加一个数字j(0~9),得到一个n位数。测试该n位数如果能被n整除,则得到一个n位逐位整除数;
递推基础为n=1位,显然有g=9个一位数j(1~9);
注意到逐位整除数的位数可能比较大,为了递推方便,设置两个二维数组:a(i,d)为k-1位的第i个逐位整除数的从高位开始第d(1~n-1)位数字,b(m,d)为递推得到k位的第m个逐位整除数的从高位开始第d(1~n)位数字;
完成从k-1位推出k位之后,需要把m赋值给g,把b数组赋值给a数组,为下一步递推做准备;
2.程序设计:
#include
int main()
{
int d,g,i,j,k,m,n,r,a[3000][30],b[3000][30];
printf("请输入逐位整除数的位数n:");
scanf("%d",&n);
g=9; /*递推基础:1位时赋初值*/
for(j=1;j<=g;j++)
a[j][1]=j;
for(k=2;k<=n;k++) /*递推位数k从2开始递增*/
{
m=0;
for(i=1;i<=g;i++) /*枚举g个k-1位逐位整除数*/
for(j=0;j<=9;j++) /*k位数的个位数字为j*/
{
a[i][k]=j;
for(r=0,d=1;d<=k;d++) /*检测k位数除k的余数r*/
{
r=r*10+a[i][d];
r=r%k;
}
if(r==0)
{
m++;
for(d=1;d<=k;d++)
b[m][d]=a[i][d]; /*满足条件的k位数赋值给b数组*/
}
}
g=m; /*递推得g个k位逐位整除数*/
for(i=1;i<=g;i++)
for(d=1;d<=k;d++)
a[i][d]=b[i][d]; /*g个b数组向a数组赋值,准备下步递推*/
}
if(g>0) /*输出n位的个数及每一个数*/
{
printf("%d位逐位整除数共%4d个:\n",n,g);
for(i=1;i<=g;i++)
{
printf(" %d:",i);
for(d=1;d<=n;d++)
printf("%d",a[i][d]);
printf("\n");
}
}
else
printf("无解!\n");
}
3.程序运行示例及其注意事项:
请输入逐位整除数的位数n:24
24位逐位整除数共 3个:
1:144408645048225636603816
2:360852885036840078603672
3:402852168072900828009216
注意:事实上,唯一的一个25位逐位整除数就是在以上第二个24位逐位整除数后加上一个数字“5”而成。而以上其他两个24位逐位整除数后加上任意一个数字后所得25位数都不能被25整除;(注意到本例n不可能大于25,在此范围内以上两个程序设计均能快速求得相应的解)
变通:修改算法,求解n位逐位整除数的个数f(n)的最大值;