逐位整除数

来源:互联网 发布:视上眼镜淘宝 编辑:程序博客网 时间:2024/05/17 23:20

逐位整除数是一类新颖有趣的整数;

定义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,此时有两个选择:

  • 若已取了n位,则输出一个n位逐位整除数,最后一位增1后继续探索;
  • 若找不到n位,则 i=i+1 继续探索下一位;

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<stdio.h>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&&i<n)         i++;      for(r=0,j=1;j<=i;j++)      {         r=r*10+a[j];         r=r%i;      }      if(r!=0)      {         a[i]=a[i]+1;  /*余数r!=0时,a[i]增1,t=1*/         t=1;         while(a[i]>9&&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数组,为下一步递推做准备;

  • 最后输出递推得到的n位逐位整除数的个数g及所有n位逐位整除数;
  • 当递增至n位没有得到n位逐位整除数时(g=0),输出“无解!”后结束;

2.程序设计:

#include<stdio.h>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:2424位逐位整除数共   3个:  1:144408645048225636603816  2:360852885036840078603672  3:402852168072900828009216

注意:事实上,唯一的一个25位逐位整除数就是在以上第二个24位逐位整除数后加上一个数字“5”而成。而以上其他两个24位逐位整除数后加上任意一个数字后所得25位数都不能被25整除;(注意到本例n不可能大于25,在此范围内以上两个程序设计均能快速求得相应的解)

变通:修改算法,求解n位逐位整除数的个数f(n)的最大值

0 0
原创粉丝点击