双码二部数序列

来源:互联网 发布:网络流行语网站 编辑:程序博客网 时间:2024/04/28 18:47

双码二部数定义:由两个不同数码组成,每个数码多于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,20173159,6(30)7(10)

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

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

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

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

1 0
原创粉丝点击