卡普雷卡数

传说数学家 卡普雷卡 (Kaprekar)偶然发现铁路旁的里程碑“3025”被雷击得一分为二:30与25.他敏锐地注意到:30+25=55,55^2=3025。
现称这样具有分段和平特性的整数为卡普雷卡数。
先探讨搜索4位卡普雷卡数的基础上引申至一般偶数位卡普雷卡数,并进一步拓广到2段和平方数。

搜索4位卡普卡雷卡数

一个4位整数分为前后两个2位数,若该数等于所分两个2位数和的平方,则称该数为4位卡普雷卡数。
试求出所有的4位卡普雷卡数。

1.说明:
设4位整数a=b*b,存在以下两个枚举方案:

(1)、循环枚举所有4位整数a,应用取整函数(int)和求余(%)把a分段为前后两个2位整数x,y,通过条件判别:若满足a=(x+y)^2且y>=10,即找到卡普雷卡数a,进行打印输出;
(2)、循环枚举2位整数b,求出a=b*b,对平方数a同上分段为前后两个2位整数x,y,进行判别:若满足b=x+y且y>=10,即找到卡普雷卡数a,进行打印输出。

显然方案二的枚举次数较少,较为简单。

2.程序设计:

#include<stdio.h> 
#include<math.h>
int main()
{
   int a,b,c,x,y;
   printf("4位卡普雷卡数:");
   c=(int)sqrt(1000);
   for(b=c+1;b<=99;b++)    /*枚举2位整数b*/
   {
      a=b*b;
      x=a/100;
      y=a%100;         /*a分为前后两个整数*/
     if(y>=10&&b==(x+y))
        printf("%d,",a);
   }
   printf("\n");
}

3.程序运行示例及其注意事项:

4位卡普雷卡数有:2025,3025,

注意:分段和条件检验中的y>=10是确保y为2位数。若去除y>=10的限制,则还有9801,该数分解的两段,前段为一个2位数98,后段是一个1位数1,不符合“分段为前后两个2位整数”的要求。

探求偶数n位卡普雷卡数

偶数n位卡普雷卡数分为前后两个n/2位整数,该数等于所分两个数和的平方;
输入偶数n(4<=n<=14),输出所有的n位卡普雷卡数。

1.说明:
注意到n超过10位,相关变量设置为双精度实型。

1)、设置枚举循环;
设n位平方数a=b*b,求出b的最小值c与最大值d,
设置b(c~d)循环,循环中a=b*b即为n位平方数。
2)、实施分段;
同时设置分段特征量w=10^(n/2),对平方数a应用取整x=floor(a/w)和求余y=fmod(a,w)计算a分段前后的两个n/2位整数x,y。
3)、分段和判别;
如果后一段首位为0,则导致整数y不足n/2位,为此需要加上条件y>=w/10,
若满足条件b=x+y且y>=w/10,即找到n位卡普雷卡数a,进行打印输出。

2.程序设计:

#include<stdio.h>
#include<math.h>
int main()
{
   double a,b,m,w,x,y;
   int k,n;
   long c,d;
   while(1)
   {
      printf("请输入偶数n位(n<=14):");
         scanf("%d",&n);
      if(n%2!=0)
         printf("对不起!你输入的不是偶数,请你重新输入!\n");
      else
         break;
   }      
      printf("%d位卡普雷卡数有: \n",n);
   for(m=1,k=2;k<=n;k++)
      m*=10;
   for(w=1,k=1;k<=n/2;k++)
      w*=10;
   c=(long)pow(m,0.5);  /*求出枚举b循环的起点*/
   d=(long)pow(10*m-1,0.5);  /*求出枚举b循环的终点*/
   for(b=c+1;b<=d;b++)
   {
      a=b*b;
      x=floor(a/w);
      y=fmod(a,w);
      if(b==x+y&&y>=w/10)  /*分段和条件检验*/
         printf("   %.0f=(%.0f+%.0f)^2 \n",a,x,y);
   }
}

3.程序运行示例及其注意事项:

请输入偶数n位(n<=14): 14
14位卡普雷卡数有:
19753082469136=(1975308+2469136)^2
24284602499481=(2428460+2499481)^2
25725782499481=(2572578+2499481)^2
30864202469136=(3086420+2469136)^2

注意:以上所得4个14位卡普雷卡数,所分的前后两段都是7位整数。

2段和平方数

作为卡普雷卡数的进一步推广,推出2段和平方数。

定义:把一个n位正整数a分为前后两段(两段的位数不要求相等,两段所生成的两个正整数的位数之和也不要求等于n),若分段的两个正整数之和的平方等于a,则称a为2段和平方数。
例如:88209=(88+209)^2,88209就是一个把自身分为两段“88”与“209”的和的平方数,即2段和平方数。

显然,前面的偶数位卡普雷卡数是偶数位2段和平方数的特例,
输入位数n(2<=n<=16),搜索并输出所有的n位2段和平方数。

1.说明:
注意到n位数比较大,n位数及其相关数据设置为双精度实型。

1)、设置枚举循环;
设a=b * b,a为n位整数,求出b的取值范围[c,d],设置枚举b(c~d)循环,循环中计算的a=b * b确保为n位平方数,
2)、实施分2段;
把一个n位数分为前后两段有n-1种分法:设置分段操作的k(1~n-1)循环,循环中模拟分段的变量w从1开始,通过自乘10可分别得w=10,100,…,10^(n-1)。应用取整x=floor(a/w)和取余y=fmod(a,w)等操作把整数a分为前后两个整数x和y。
3)、分段和条件检验;
在分段操作的k(1~n-1)循环中,每分段得两个整数x和y,检验若b=x+y,则满足分段和平方数条件,
注意到如果后段的首位可能为0,则两个正整数x,y的位数之和可能小于n,这是允许的;如果后段全部为0,则整数y为0而非正整数,这是不允许的,
因而在分段和条件检验中,除了检验b=x+y之外,需要加上条件y>0 。

2.程序设计:

#include<stdio.h>
#include<math.h>
int main()
{
   double a,b,m,w,x,y;
   long c,d;
   int k,n,s=0;
   printf("请输入正整数n(2<=n<=16):");
      scanf("%d",&n);
   for(m=1,k=2;k<=n;k++)
      m*=10;
   c=(long)pow(m,0.5);
   d=(long)pow(10*m-1,0.5);
   for(b=c+1;b<=d;b++)
   {
      a=b*b;    /*a位n位平方数*/
      w=1;
      for(k=1;k<=n-1;k++)
      {
         w*=10;
         x=floor(a/w);
         y=fmod(a,w);  /*n位平方数a分为前后两段x,y*/
         if(b==x+y&&y>0)  /*分段和检验*/
         {
            s++;
            printf("  %.0f=(%0.f+%0.f)^2 \n",a,x,y);
         }
      }
   }
   if(s>0)
      printf("共%d个%d位2段和平方数。\n",s,n);
   else printf("没有%d位2段和平方数。\n",n);
}

3.程序运行示例及其注意事项:

请输入正整数n(3<=n<=15):11
 20408122449=(20408+122449)^2
 21948126201=(21948+126201)^2
 33058148761=(33058+148761)^2
 35010152100=(35010+152100)^2
 43470165025=(43470+165025)^2
共5个11位2段和平方数。

注意:运行程序可知,若位数n为奇数时,所分两段位数一般只相差1(如n=11时,一段为5位,另一段为6位);若位数n为偶数时,所分两段位数相等(如n=14时,两段都为7位)。

因此,对以上程序前后两端实施n-1种分发应该可以简化:

#include<stdio.h>
#include<math.h>
int main()
{
   double a,b,m,w,x,y;
   long c,d;
   int k,n,s=0;
   printf("请输入正整数n(3<=n<=15):");
      scanf("%d",&n);
   for(m=1,k=2;k<=n;k++)
      m*=10;
   c=(long)pow(m,0.5);
   d=(long)pow(10*m-1,0.5);
   for(b=c+1;b<=d;b++)
   {
      a=b*b;    /*a位n位平方数*/
     for(w=1,k=1;k<=n/2;k++)
        w*=10;
      for(k=0;k<=n%2;k++)  /*由n的奇偶控制循环次数*/
      {

         x=floor(a/w);
         y=fmod(a,w);  /*n位平方数a分为前后两段x,y*/
         if(b==x+y&&y>0)  /*分段和检验*/
         {
            s++;
            printf("  %.0f=(%0.f+%0.f)^2 \n",a,x,y);
         }
      w*=10;
      }
   }
   if(s>0)
      printf("共%d个%d位2段和平方数。\n",s,n);
   else printf("没有%d位2段和平方数。\n",n);
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值