古尺神奇

有一年代尚无考究的古尺长29寸,因磨损日久尺上的刻度只剩下7条,其余刻度均已不复存在,神奇的是,使用该尺仍可一次性度量1~29之间任意整数寸长度;

设计程序,试确定古尺上7条刻度的位置分布;


7刻度度量29尺长

1.说明:

这是一道有一定难度的实用性较强的趣题;

要使长为29(单位略)的直尺一次性度量1~29之间的任意整数长(简称完全度量),少于7条刻度是不行的;

事实上,假若只有6条刻度,连同尺的两条端线共8条,8取2的组合数为28,即6条刻度的直尺最多只有28种度量长度,显然小于29;

为了寻求实现直尺完全度量的7条刻度的分布位置,设置数组a(8)和b(36),尺左端为a(0)=0,a(i)(i=2,……,7)在2~s-1中取不重复的数,不妨设:

  • 2<=a(2)< a(3)<……< a(7)<=s-1

设置a(2),a(3),……,a(7)循环: a(2)取2开始,以后a(i)从a(i-1)+1开始递增1取值,直至s-(8-i)为止,这样可以避免重复取值

当i=7时,7条刻度连同尺的两条端线共9条,组合数为36,36种长度赋给b数组元素b(1),b(2),b(3),……,b(36);

为判定某种刻度分布位置能否实现完全度量,设置特征量u:对于1<=d<=s的每一个长度d,如果在b(1)~b(36)中存在某一元素等于d,特征量u值增1,最后,若u=29,说明从1至尺长29的每一个整数d都有一个b(i)相对应,即实现完全度量,打印直尺的段长序列;

2.程序设计:

#include<stdio.h>
int main()
{
   int c,d,j,k,s,t,u,a[9],b[37];
   printf("7刻度分29尺长为8段,段长序列为:\n");
   s=29;
   a[0]=0;
   a[1]=1;
   a[8]=s;
   c=0;
   for(a[2]=2;a[2]<=s-6;a[2]++)
    for(a[3]=a[2]+1;a[3]<=s-5;a[3]++)
     for(a[4]=a[3]+1;a[4]<=s-4;a[4]++)
      for(a[5]=a[4]+1;a[5]<=s-3;a[5]++)
       for(a[6]=a[5]+1;a[6]<=s-2;a[6]++)
        for(a[7]=a[6]+1;a[7]<=s-1;a[7]++)
        {
           for(t=0,k=0;k<=7;k++)
              for(j=k+1;j<=8;j++)
              {
                 t++;     /*序列部分和赋值给b数组*/
                 b[t]=a[j]-a[k];
              }
           for(u=0,d=1;d<=s;d++)
              for(k=1;k<=36;k++)
                 if(b[k]==d)    /*检验b数组取1~s有多少个*/
                 {
                    u+=1;
                    k=36;
                 }
           if(u==s)    /*b数组值包括1~s所有整数*/
           {
              if((a[7]!=s-1) || (a[7]==s-1) && (a[2]<=s-a[6]))
              {
                 c++;
                 printf("NO%d:",c);  /*输出解的段长序列*/
                 for(k=1;k<=7;k++)
                    printf("%2d,",a[k]-a[k-1]);
                 printf("%2d \n",s-a[7]);
              }
           }
        }
   if(c>0)
      printf("共有以上%d个解\n",c);    /*输出解的个数*/
}

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

7刻度分29尺长为8段,段长序列为:
NO1: 1, 1,12, 4, 3, 3, 3, 2
NO2: 1, 2, 3, 7, 7, 4, 4, 1
NO3: 1, 3, 6, 6, 6, 2, 3, 2
共有以上3个解

注意:

  • 为便于验证,直尺的刻度分布采用段长序列即相邻两刻度之间的相距间隔来输出,对于7刻度而言,尺长29有以上3个解,即题目探求古尺刻度分布

  • 以上输出结果是否能“完全度量”,不妨以第2个解予以展示,度量值为相连的若干段长之和,从小到大依次为:1,2,3,4,2+3,1+2+3,7,4+4,4+4+1,3+7,7+4,2+3+7,1+2+3+7,7+7,7+4+4,7+4+4+1,3+7+7,7+7+4,2+3+7+7,1+2+3+7+7,3+7+7+4,7+7+4+4,7+7+4+4+1,1+2+3+7+7+4,3+7+7+4+4,3+7+7+4+4+1,2+3+7+7+4+4,1+2+3+7+7+4+4,1+2+3+7+7+4+4+1=29

可见,7刻度可完全度量29尺长;


拓广到n条刻度s尺长

一般地,探索尺长为s、刻度数为n(s、n均为正整数)的完全度量问题上;

1.说明:

为了寻求实现尺长s完全度量的n条刻度的分布位置,设置以下两个数组:数组a元素a(i)为第i条刻度距离尺左端线的长度,约定a(0)=0和a(n+1)=s对应尺的左右端线,注意到尺的两端至少有一条刻度距端线为1(否则长度s-1不能度量),不妨设a(1)=1,其余的a(i)(i=2,……,n)在2~s-1中取数,不妨设:

  • 2<=a(2)< a(3)<……< a(n)<=s-1

从a(2)取2开始,以后a(i)从a(i-1)+1开始递增1取值,直至s-(n+1)+i为止;

当i=n时,n条刻度连同尺的两条端线共n+2条,从n+2取2的组合数为C(n+2,2),记为m,显然有:

  • m=C(n+2,2)=(n+1)(n+2)/2

试把m个长度赋给b数组元素b(1),b(2),……,b(m),为判定某种刻度分布能否实现完全度量,设置特征量u,对于1<=d<=s的每一个长度d,如果在b(1)~b(m)中存在某一元素等于d,特征量u值增1;

最后,若u=s,说明从1至尺长s的每一个整数d都有一个b(i)相对应,即达到完全度量,于是输出带n条刻度分布的直尺,并打印相应的段长序列;

若i< n,i增1后a[i]=a[i-1]+1后继续探索;

当i>1时a(i)增1继续,至a(i)=s-(n-1)+i时回溯;

**2.程序设计:

#include<stdio.h>
int main()
{
   int d,i,j,k,t,u,s,m,n,a[30],b[300];
   printf("尺长s,寻求n条刻度分布,请确定s,n:");
   scanf("%d,%d",&s,&n);
   a[0]=0;
   a[1]=1;
   a[n+1]=s;
   m=(n+2)*(n+1)/2;
   i=1;
   a[i]=2;
   while(1)
   {
      if(i<n)
      {
         i++;
         a[i]=a[i-1]+1;
         continue;
      }
      else
      {
         for(t=0,k=0;k<=n;k++)
            for(j=k+1;j<=n+1;j++)
            {
               t++;             /*序列部分和赋值给b数组*/
               b[t]=a[j]-a[k];
            }
         for(u=0,d=1;d<=s;d++)
            for(k=1;k<=m;k++)
               if(b[k]==d)      /*检验b数组取1~s有多少个*/
               {
                  u+=1;
                  k=m;
               }
         if(u==s)
         {
            if((a[n]!=s-1) || (a[n]==s-1) && (a[2]<=s-a[n-1]))
            {
               printf("◤");         /*输出尺额上边*/
               for(k=1;k<=s-1;k++)
                  printf("▔");
               printf("◥\n");
               printf("▍");
               for(k=1;k<=n+1;k++)     /*输出尺的数字标注*/
               {
                  for(j=1;j<=a[k]-a[k-1]-1;j++)
                     printf("  ");
                  if(k<n+1)
                     printf("%2d",a[k]);
                  else
                     printf("▍\n");
               }
               printf("◣");
               for(k=1;k<=n+1;k++)
               {
                  for(j=1;j<=a[k]-a[k-1]-1;j++)
                     printf("▔");
                  if(k<n+1)
                     printf("╪");
                  else
                     printf("◢\n");
               }
               printf("直尺%d段的段长序列为:",n+1);  /*输出段长序列*/
               for(k=1;k<=n;k++)
                  printf("%2d,",a[k]-a[k-1]);
               printf("%2d \n",s-a[n]);
            }
         }
      }
      while(a[i]==s-(n+1)+i && i>1)  /*调整或回溯*/
         i--;
      if(i>1)
         a[i]++;
      else
         break;
   }
}

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

尺长s,寻求n条刻度分布,请确定s,n:36,8
 ▼▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▼
|  1    3     6          13         20          27      31          35     |                     
▼▔|▔▔|▔▔▔|▔▔▔▔▔▔|▔▔▔▔▔▔|▔▔▔▔▔▔|▔▔▔▔|▔▔▔▔▔▔|▔▔▔▼直尺9段的段长序列为:1,2,3,7,7,7,4,4,1

对应于n=8,输入s=37,38,……,45,都没有输出,说明8条刻度能完成完全度量的长度最大值36;

顺便指出网上某些关于Colomb尺上7刻度能完全度量44尺长、8刻度能完全度量55尺长等结论显然不成立;

思考:

由以上程序得到的8刻度分布的段长序列与前面7刻度分布的第2个解比较,两个解首均为“1,2,3”,尾均为“4,4,1”,首尾完全相同,只是中间相差一个“7”段,由此可以总结出以下一般结论:

对于n(n>6)条刻度把直尺分割为如下分布的n+1段:

  • 1,2,3,7,7,……,7,4,4,1

其中尺的中部有连续n-5个“7”段,对应尺长为7n-20,则该尺可实现完全度量;

请证明以上结论;

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值