数码串珠

原创 2017年01月03日 07:29:38

在某寺遗址考古发掘中意外发现一串奇特的数码珠串,珠串上共串缀有6颗宝珠,每一宝珠上都刻有一个神秘的整数,长期以来,无人知晓这6颗数码串珠究竟有什么作用,专家通过考证,揭示这一数码串珠具有以下奇异特性:

(1)、这6颗宝珠上的整数互不相同,6个整数之和为31

(2)、沿珠串相连的若干颗(1~6颗)珠上整数之和为1,2,……,31不间断,这一象征祥瑞的特性表现为完全覆盖,即可覆盖区间[1,31]中的所有整数

请确定珠串上6颗宝珠上的整数及其相串的顺序;


6个整数和为s的全覆盖

1.说明:

为叙述方便,称沿圆圈若干个相连整数之和为“部分和”,部分和为区间[1,31]中的所有整数不间断称为“完全覆盖”;

问题是要在如图所示圆上的6个小圆圈中各填入一个整数,这6个整数之和为31,且沿圆相连的若干个(1~6个)小圆圈中整数之和覆盖区间[1,31]中的所有整数;

佛珠数码示意图

为了确定和为31的6个整数取值及检验这6个整数顺序是否能完全覆盖,设置,设置a数组作标记,起点为a(0)=0,约定a(1)-a(0)为第1个数,a(2)-a(1)为第2个数,……,一般地a(i)-a(i-1)为第i个数;

因为共6个数,显然a(6)=31且与起点a(0)重合,因为6个数中至少有一个数为1(否则不能覆盖1),不妨设第1个数为1,即a(1)=1;

串上6个数的每一个数都可以与(约定顺时针方向)相连的1,2,……,5个数组成部分和,易知共有31个部分和;

为构造部分和方便,定义a(7)与a(1)重合,即a(7)=a(6)+a(1);a(8)与a(2)重合,即a(8)=a(6)+a(2);……;最后有a(11)与a(5)重合,即a(11)=a(6)+a(5);

设置b数组存储部分和,变量u统计b数组覆盖区间[1,31]中数的个数,若u=30(31本身显然覆盖,除去不计),即完全覆盖,输出和为31时的6个整数序列;

2.程序设计:

#include<stdio.h>
int main()
{
   int c,d,i,j,s,t,u,a[20],b[300];
   s=31;
   c=0;
   printf("6珠和为31的解有:\n");
   a[0]=0;
   a[1]=1;
   a[6]=s;
   for(a[2]=a[1]+1;a[2]<=27;a[2]++)
    for(a[3]=a[2]+1;a[3]<=28;a[3]++)
     for(a[4]=a[3]+1;a[4]<=29;a[4]++)
      for(a[5]=a[4]+1;a[5]<=30;a[5]++)
      {
         for(i=7;i<=11;i++)
            a[i]=31+a[i-6];
         for(t=0,i=0;i<=5;i++)
            for(j=i+1;j<=i+5;j++)    /*除31外,产生30个部分和*/
            {
               t++;               
               b[t]=a[j]-a[i];
            }
         u=0;
         for(d=1;d<=30;d++)
            for(i=1;i<=30;i++)
               if(b[i]==d)       /*b有[1,30]中的一个数,u增1*/
               {
                  u+=1;
                  i=30;
               }
         if(u==30)     /*u=30时为完全环覆盖*/
         {
            c++;
            printf(" (%2d) %2d",c,1);
            for(i=1;i<=5;i++)
               printf(",%2d",a[i+1]-a[i]);
            if(c%2==0)
               printf("\n");
         }
      }
   if(c>0)
      printf("共有以上%d个解\n",c);
} 

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

6珠和为31的解有:
 ( 1)  1, 2, 5, 4, 6,13 ( 2)  1, 2, 7, 4,12, 5
 ( 3)  1, 3, 2, 7, 8,10 ( 4)  1, 3, 6, 2, 5,14
 ( 5)  1, 5,12, 4, 7, 2 ( 6)  1, 7, 3, 2, 4,14
 ( 7)  1,10, 8, 7, 2, 3 ( 8)  1,13, 6, 4, 5, 2
 ( 9)  1,14, 4, 2, 3, 7 (10)  1,14, 5, 2, 6, 3
共有以上10个解

注意:

  • 所输出的解中没有出现重复整数,其和均为31,且满足“完全满足”的要求,其中第3个解的数码珠串排列如图所示;不妨以此图解展示其部分和(从小到大)“完全覆盖”的特性:
    1,2,3,1+3,3+2,1+3+2,7,8,2+7,10,10+1,3+2+7,1+3+2+7,10+1+3,7+8,16~30为以上部分和的“补部分和”,31为序列所有整数之和

  • 同时观察到,这10个解两两配对,互为顺时针与逆时针关系,例如其中第1个解与第8个解是一对等;

数码6珠串示意图


拓广到n个整数和为s的全覆盖

一般地,求解圆环上的n个整数序列,其和为s,沿环的部分和完全覆盖区间[1,s]上的所有整数;

下面采用回溯设计求解;

1.说明:

(1)、数组设置

设置a数组做标记,起点为a(0)=0,约定a(1)-a(0)为第1个数,a(2)-a(1)为第2个数,……,一般地a(i)-a(i-1)为第i个数,因为共n个数,显然刻度a(n)=s且与起点a(0)重合;

因为n个数中至少有一个数为1(否则不能覆盖1),不妨设第1个数为1,即a(1)=1;

圆环上的n个数的每一个数都可以与(约定顺时针方向)相连的1,2,……,n-1个数组成部分和,为构造部分和方便,定义a(n+1)与a(1)重合,即a(n+1)=s+a(1);a(n+2)与a(2)重合,即a(n+2)=s+a(2);……;最后有a(2n-1)与a(n-1)重合,即a(2n-1)=s+a(n-1);

(2)、判别完全覆盖

设置b数组存储部分和,变量u统计b数组覆盖区间[1,s]中数的个数,若u=s-1(s本身显然覆盖,出去不计),即完全覆盖,输出和为时的序列解,

(3)、取数与回溯

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

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

变量s与n的值从键盘输入,运行程序时,选择s是从n(n-1)+1开始,逐渐取值输入,最先所得解为对应n的s最大值,然后再从这些解中选取没有相同整数的解;

2.程序设计:

#include<stdio.h>
int main()
{
   int c,d,i,j,k,t,u,s,n,a[30],b[300];
   printf("n个整数和为s,部分和完全覆盖s,请确定s,n:");
   scanf("%d,%d",&s,&n);
   a[0]=0;
   a[1]=1;
   a[n]=s;
   i=2;
   a[i]=2;
   c=0;
   while(1)
   {
      if(i<n-1)
      {
         i++;
         a[i]=a[i-1]+1;
         continue;
      }
      else
      {
         for(k=n+1;k<=2*n-1;k++)
            a[k]=s+a[k-n];
         for(t=0,k=0;k<=n-1;k++)
            for(j=k+1;j<=k+n-1;j++)  /*序列部分和赋值给b数组*/
            {
               t++;
               b[t]=a[j]-a[k];
            }
         for(u=0,d=1;d<=s-1;d++)
            for(k=1;k<=t;k++)
               if(b[k]==d)  /*检验b数组取1~s有多少个*/
               {
                  u++;
                  k=t;
               }
         if(u==s-1)         /*b数组值包括1~s所有整数*/
         {
            c++;
            printf("%2d:1",c);
            for(k=2;k<=n;k++)
               printf(",%4d",a[k]-a[k-1]);   /*输出串珠上的数码*/
            printf("\n");
         }
      }
      while(a[i]==s-n+i && i>1)   /*调整或回溯*/
         i--;
      if(i>1)
         a[i]++;
      else
         break;
   }
}

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

n个整数和为s,部分和完全覆盖s,请确定s,n:21,5
 1:1,   3,  10,   2,   5
 2:1,   5,   2,  10,   3

容易验证,圆环上的5个数组成的部分和为21个,“完全覆盖”的实现说明了所有21个部分和没有重复的

最后指出,“古尺神奇”是在长度为s的直尺上分布的n条刻度分割的n+1个整数(段长)对s的全覆盖,而“数码串珠”是在圆环上分布的和为s的n个整数对s的全覆盖,后者是对前者的引申,实际上是环序列对一般序列的引申;

就构成部分和而言,在环上的整数利用率高些,因此后者的覆盖效率高于前者;

版权声明:本文为博主原创文章,博主欢迎大家转载!

bzoj P2560 串珠子

传送门 第一道子集dp。(感觉很像状压dp。。 好弱啊我看了好多大神的博客才勉强看懂 g[s]表示s状态下的所有情况,即s状态下的点两两之间任意连边(包括不连边),f[s]表示s状态下的合法情况...

多针头自动串珠机

  • 2014年10月17日 12:51
  • 48KB
  • 下载

字串珠玑.pdf

  • 2011年10月19日 17:10
  • 2.24MB
  • 下载

uva10054--欧拉回路--串珠子

题意: 给出不同颜色的珠子,珠子的两边有两种颜色,串珠子时相邻的珠子颜色要相同。比如12就可以接在32的后面,注意最后一颗珠子要和第一颗珠子要连在一起,也就是说要形成一个回路。 思路: 无脑df...

DIY串珠网站策划书

  • 2015年10月24日 14:10
  • 48KB
  • 下载

一个简单的串珠flash

  • 2012年10月04日 13:23
  • 11KB
  • 下载

Arduino学习(八) 数码管

一、了解数码管(Digitron) 数码管, 又称LED数码管, 是由八段发光二极管(LED)封装在一起组成“8”字型的器件,外加一个小数点。 数码管动态显示接口是单片机中应用最为广泛的一...
  • c80486
  • c80486
  • 2016年09月30日 00:45
  • 3501

好用的查经工具-串珠圣经

  • 2010年02月10日 14:35
  • 6.85MB
  • 下载

VerilogHDL实现FPGA的数码管驱动

1、用八位数码管实现静态显示,首先让8位数码管所有位全亮,再全灭,再同时显示0-f的变化(一秒为变化周期)。module shumaguan(mainclk,/*主时钟*/ seg_d...

移动拼图游戏(八数码问题)A*版

小时候玩过的移动拼图游戏。有一个3*3的棋盘,其中有0-8这9个数字,0表示空格,其他的数字可以和0交换位置。 求从初始状态 2 3 0 7 1 6 5 8 4 变到目标状态 1 2 3 ...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:数码串珠
举报原因:
原因补充:

(最多只允许输入30个字)