逐位整除数

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

定义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
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数组,为下一步递推做准备;

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

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)的最大值

你可能感兴趣的:(致美C程序,特殊整数)