双码二部数序列

双码二部数定义:由两个不同数码组成,每个数码多于1位时相连而不分开的正整数称为双码二部数,其中处于高位相连数字称为高部,处于低位相连数字称为低部

例如330是一个3位双码二部数:高部数字为3,高部位数为2;低部数字为0,底部位数为1,而333只有一个数码,4407有三个数码,4474的数码4呈分开状态,都不是双码二部数;

试统计n位双码二部数的个数,并求出n位双码二部数从小到大排序序列的第m项;

输入正整数n(1< n< 10000)与m,输出n位双码二部数的个数,同时输出n位双码二部数序列的第m项的高部数字(高部位数)和低部数字(底部位数),如果m大于n位双码二部数的个数,则输出“0”;

1.递增枚举要点:

设n(n>1)位双码二部数为a……ab……b(1<=a<=9,0<=b<=9),其高部数字a有la位,低部数字b有lb位,显然有:

  • la+lb=n (1<=la<=n-1)

为了确保从小到大枚举双码二部数,要注意枚举循环的先后次序:首先,高部数字a必须从小到大,范围为1~9;当a确定后,高部位数la简单地从小到大或从大到小都不能确保双码二部数从小到大变化,需要配合b分以下3步完成,为便于理解,以n=4,a=4的递增进程实施标注;

(1)、la增长(1~n-2)段,lb=n-la,b递增(0~a-1)取值;

4000  4111  4222  4333   (la=1, lb=3, b: 0~3)
4400  4411  4422  4433   (la=2, lb=2, b: 0~3)

(2)、la与lb取定值段,la=n-1,lb=1,b递增(0~9)取值(当b=a时跳过);

4440  4441  4442  4443  4445  4446  4447  4448  4449
       (la=3, lb=1, b: 0~9, 其中b=4时跳过)

(3)、la减小(n-2~1)段,lb=n-la,b递增(a+1~9)取值;

4455  4466  4477  4488  4499   (la=2, lb=2, b: 5~9)
4555  4666  4777  4888  4999   (la=1, lb=3, b: 5~9)

以上3步骤中每一步骤都是递增的,且3个步骤衔接中没有重复与遗漏,从而可能确保n位的双码二部数从小到大递增,没有重复与遗漏;

2.枚举程序设计:

#include<stdio.h>
#include<math.h>
int main()
{
   int a,b,a0,b0,n,la,lb,la0;
   long m,s;
   printf("请输入整数n,m: ");
   scanf("%d,%ld",&n,&m);
   s=0;
   for(a=1;a<=9;a++)       /*高部数字a从小到大枚举*/
   {
      for(la=1;la<=n-2;la++) /*高部数字la分3个步骤枚举*/
      {
         lb=n-la;
         for(b=0;b<=a-1;b++)
         {
            s++;             /*变量s统计个数*/
            if(s==m)         /*记录第m个数的信息*/
            {
               a0=a;
               b0=b;
               la0=la;
            }
         }
      }
      la=n-1;
      lb=1;
      for(b=0;b<=9;b++)
      {
         if(a!=b)               /*当a=b时跳过*/
         {
            s++;
            if(s==m)
            {
               a0=a;
               b0=b;
               la0=la;
            }
         }
      }
      for(la=n-2;la>=1;la--)
      {
         lb=n-la;
         for(b=a+1;b<=9;b++)
         {
            s++;
            if(s==m)
            {
               a0=a;
               b0=b;
               la0=la;
            }
         }
      }
   }
   if(s>=m)
      printf(" %ld,%d(%d)%d(%d)\n",s,a0,la0,b0,n-la0);
   else
      printf(" %ld,%d\n",s,0);
}

3.简化枚举循环设计:

#include<stdio.h>
int main()
{
   int a,b,a0,b0,n,la,la0;
   long m,s;
   printf("请输入整数n,m: ");
   scanf("%d,%ld",&n,&m);
   s=1;
   a=1;
   b=0;
   la=1;                 /*默认n位第1个为1后n-1个0*/
   while(la<n-1 || a<9 || b<8)
   {
      s++;
      if(b==9)           /*此时b不能增1,有以下两种选择*/
         if(la==1)       /*①a增1后,b从0开始*/
         {
            a++;
            b=0;
         }
         else            /*②a段长增1后,b从a+1开始*/
         {
            la--;
            b=a+1;
         }
      else if(b!=a-1)    /*a与la不变,b增1*/
         b++;            
      else if(la!=n-1)   /*a段长增1后,b从0开始*/  
      {
         la++;
         b=0;
      }
      else if(b<8)       /*b增2跳过a=b情形*/
         b+=2;
      if(s==m)
      {
         a0=a;
         b0=b;
         la0=la;
      }
   }
   if(s>=m)
      printf(" %ld,%d(%d)%d(%d)\n",s,a0,la0,b0,n-la0);
   else
      printf(" %ld,%d\n",s,0);
}

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

请输入整数n,m: 40,2017
3159,6(30)7(10)

可知40位双码二位数共有3159个,40位双码二部数升序序列的第2017项高部30个“6”,低部10个“7”;

由第2017项的数据看似非常大,但枚举次数只有3159次;

枚举循环次数即n为双码二部数的个数,随着n的增大运算显著增长,但对于n<10000,枚举时间是可以接受的;

双码二部数的递增枚举是比较复杂的,也容易出错,这一设计提醒我们不要轻视枚举,枚举设计可以解决一些较为复杂的搜索案例;

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值