棋盘的完美覆盖(多米诺骨牌完美覆盖)&&幻方(魔方阵)

标签: 数学
3372人阅读 评论(0) 收藏 举报
分类:

棋盘的完美覆盖:

一张8行8列的棋盘一共有64个方格,用一些形状相同的多米诺骨牌覆盖,每一张覆盖相邻的两个方格,没有相互重叠,能用32张这样的多米诺骨牌完全覆盖整张棋盘称为多米诺骨牌完美覆盖或者盖瓦。这样的完美覆盖是存在的,而且不止一种方式,一共有12988816=2^4*17^2*53^2种。那么对于一般的m行n列的棋盘是否存在着多米诺骨牌完美覆盖呢?充要条件是m*n是偶数,这等价于分子物理学中的二聚物问题。有这样的问题:如果把8行8列的棋盘的一条对角线上的两个角的方格去掉,那么完美覆盖还有多少种呢?这样分析:每一张骨牌覆盖相邻的两个方格,那么就假设棋盘是黑白相间的,呈现这样的场景(1代表黑,0代表白):

去掉的两个方格必然是相同的颜色,于是原来32张黑色和32张白色变成了30黑色(白色),32白色(黑色)。如果31张骨诺牌能够完美覆盖,那么就产生了这样的关系式:31(black+white)=30black+32white [or: 30white+32black] 这显然是不成立的。所以一种完美覆盖都不存在。

拓展:如果棋盘的规格是m*n,且一张牌的长度是b(称作b格牌),那么这样的棋盘能够被b格牌完美覆盖吗?显然,想要完美覆盖,b必然是m*n的因子,这就是充分条件:b是m或者n的因子(联系实际)。事实上有这样的结论:m*n的棋盘有b格牌的完美覆盖当且仅当b是m或者n的一个因子。

幻方:

一个由数字1,2,3--n^2组成n行n列的n阶的幻方,满足每一行每一列两条对角线上的数字之和是等值的,假设这样的值是s。那么有这样的等式:n*s=1+2+3+--+n^2=(n^2+1)/2*n^2. -->s=n*(n^2+1)/2. 所以我们可以推断2阶的魔方阵是不存在的,不然s=5啊,显然这是不可能的。幻方的构造和很多方法,n为奇数时有这样一种应用较广的构造方法:首先把1放在第一行的中间,然后按照左下方到右上方的顺序摆放各个数字(行数i和列数j的变化趋势:向量(i-1,j+1)),遇到特殊的情况:

(1)当下一个数字到达已有数字的位置或者四个对角线方向的方阵外时,直接把新的数字放到上一个数字的下面。

(2)当下一个数字的行数到了0时,行数变为n,列数照常加1。

(3)当下一个数字的列数到了n+1时,列数变为1,行数照常减1。

奇数阶幻方(16阶内):

#include"stdio.h"
void xiabiao(int &a, int &b,int n)
{
	a-=1;
	b+=1;
	if(a<0 && b>n-1){ a+=2; b-=1; }
	if(a<0)a=n-1;
	if(b>n-1)b=0;
}
main()
{
     int  m[16][16],n;/*h表示最中间的列数*/
     int i,j,k=1;
     while(~scanf("%d",&n)&&n) //enter a number n. 
     {
		 if(n%2==0 || n<1 || n>16)continue; 		 
		 for(i=0;i<n;i++)
		    for(j=0;j<n;j++)
                        m[i][j]=1;
                 i=0;  
		 j=n/2; 
		 k=1;  
		 while(k<n*n)
		 {
			 xiabiao(i,j,n);
			 if((m[i][j]<k && m[i][j]!=1) || (i==0 && j==n/2)){ i+=2; j-=1; }
			 m[i][j]=++k;
		 }
		 for(i=0;i<n;i++)
		 {
		     for(j=0;j<n;j++)
			     printf("%5d",m[i][j]);
		     printf("\n");
		 }
	 }
}

当n是偶数时分成4k(双偶数)和4k+2(单偶数)阶讨论:对于4k,先说说最简单的4阶情况。先把所有的元素从左到右从上到下顺序填写完整,再把对角线 上的所有元素标记,其他元素按照中心对称位置关系两两互换。即可达到幻方效果。将其推广,当k=2,3,4……时同样先顺序填写,再把整个方阵划分成(n/4)*(n/4)个4阶阵,把所有的四阶阵两条对角线的元素标记固定不动,然后再把n*n的方阵的所有非对角线元素以方阵中心为对称点进行中心对称互换(那么对称点的位置关系就是(x1,y1)+(x2,y2)=(n+1,n+1)),最终即可构成n阶幻方阵。

双偶数阶幻方(16阶内):

#include"stdio.h" 
#include"string.h"
int m[17][17],n;
bool vis[17][17];
void swap(int *a,int *b){
	int t=*a;
	*a=*b;
	*b=t;
}
void show(){
	int i,j;
	for(i=1;i<=n;i++){
			for(j=1;j<=n;j++){
				printf("%5d",m[i][j]);
			}
			printf("\n");
	}
}
void block(){  
    int i,j,k,re=n/4;
    for(i=0;i<re;i++){
    	for(j=0;j<re;j++){
    		for(k=1;k<=4;k++){
			    vis[k+4*i][k+4*j]=vis[k+4*i][4+1-k+4*j]=1;
	        }
    	}
    }
	for(i=1;i<=n/2;i++){
		for(j=1;j<=n;j++){
			if(vis[i][j])continue;
			swap(&m[i][j],&m[n+1-i][n+1-j]);
		}
    }
}
int main(int argc, char *argv[]) {
	freopen("cin.txt","r",stdin);
	freopen("cout.txt","w",stdout);
	int i,j,k;
	while(~scanf("%d",&n)&&n){
		memset(vis,0,sizeof(vis));
		k=1;
		for(i=1;i<=n;i++){
			for(j=1;j<=n;j++){
				m[i][j]=k++;
			}
		}
		//show();
		block();
		show();
	}
	return 0;
}

4k+2阶的幻方则稍复杂一点,有这样的方法:现将方阵划分成两个区,边界上所有元素为一个区A,边界内的所有元素构成一个区B,B区即是一个4k阵,把8k+3--16k^2+8k+2的数字填入双偶数阵按照前面的方法进行变化。然后剩下的元素放到边界进行试调,直到满足幻方的条件即可。当然这样在计算机上很难实现。还有一种易于实现的方法:把方阵分为A,B,C,D四个象限,这样每一个象限肯定是奇数阶。依次在A象限,D象限,B象限,C象限按奇数阶幻方的填法填数。以6阶为例如同:

在A象限的中间行、中间格开始,按自左向右的方向,标出k格。A象限的其它行则标出最左边的k格。将这些格,和C象限相对位置上的数,互换位置。

在B象限任每行的中间格,自右向左,标出k-1列。(注:6阶幻方由于k-1=0,所以不用再作B、D象限的数据交换), 将B象限标出的这些数,和D象限相对位置上的数进行交换,就形成幻方。

单偶数阶幻方(16阶内):

#include <iostream>
#include<cstdio> 
#include<cstring> 
using namespace std;
int m[17][17],tag[17][17],n;
int i,j,k;
void show(){ 
    for(i=1;i<=n;i++){  
         for(j=1;j<=n;j++){  
              printf("%5d",m[i][j]);  
         }  
         printf("\n");  
    }  
}
void inital(){ //(1,1),(1,n/2+1),(1+n/2,1),(1+n/2,1+n/2)
	int num;  
	memset(m,0,sizeof(m));
	int lo[4][2]={{0,0},{n/2,n/2},{0,n/2},{n/2,0}};
    for(k=0;k<4;k++){  
        num=1+(n/2)*(n/2)*k;
        i=lo[k][0]+1;    
        j=n/2/2+lo[k][1]+1;   
        int ik=num;    
        m[i][j]=ik++; 
        while(ik<num+(n/2)*(n/2))  
       {  
		 i-=1;  
         j+=1;  
         if(i<lo[k][0]+1&& j>n/2+lo[k][1]){ i+=2; j-=1; }  
         if(i<lo[k][0]+1)i=n/2+lo[k][0];  
         if(j>n/2+lo[k][1])j=1+lo[k][1];   
		 if((m[i][j]<ik && m[i][j])){ i+=2; j-=1; }   
		 m[i][j]=ik++; 
       }  
    }  
}
void write(){ 
    memset(tag,0,sizeof(tag));
	j=1+n/2/2;
	k=n/4;
	while(k--){
		tag[n/2/2+1][j++]=1;
	}
	for(i=1;i<=n/2;i++){
		if(i==n/2/2+1)continue;
		for(j=1;j<=n/4;j++)tag[i][j]=1;
	}
	for(i=1;i<=n/2;i++){
		j=n/2+n/2/2+1;
		k=n/4-1;
		while(k--){
			tag[i][j--]=1;
		}
	}
}
void showtag(){
	for(i=1;i<=n;i++){
		for(j=1;j<=n;j++){
			printf("%5d",tag[i][j]);
		}
		cout<<endl;
	}
} 
void swap(int &a,int &b){
	int t=a;
	a=b;
	b=t;
}
void change(){
	for(i=1;i<=n/2;i++){
		for(j=1;j<=n;j++){
			if(tag[i][j])swap(m[i][j],m[i+n/2][j]);
		}
	} 
}
int main(int argc, char *argv[]) {
	freopen("cin.txt","r",stdin);
	freopen("cout.txt","w",stdout); 
	while(cin>>n&&n){
		inital();
		write();
		//showtag();
		change();
		show();
	}
	return 0;
}
/*
6阶:   
   35    1    6   26   19   24
    3   32    7   21   23   25
   31    9    2   22   27   20
    8   28   33   17   10   15
   30    5   34   12   14   16
    4   36   29   13   18   11
10阶:
   92   99    1    8   15   67   74   26   58   65
   98   80    7   14   16   73   55   32   64   66
    4    6   88   95   22   54   56   38   70   72
   85   87   19   21    3   60   62   44   71   53
   86   93   25    2    9   61   68   50   52   59
   17   24   76   83   90   42   49   51   33   40
   23    5   82   89   91   48   30   57   39   41
   79   81   13   20   97   29   31   63   45   47
   10   12   94   96   78   35   37   69   46   28
   11   18  100   77   84   36   43   75   27   34
14阶:
  177  186  195    1   10   19   28  128  137   97   50  108  117  126
  185  194  154    9   18   27   29  136  145   56   58  116  125  127
  193  153  155   17   26   35   37  144  104   57   66  124  133  135
    5   14   16  172  181  183   45  103  112   65   74  132  134  143
  160  162  171   33   42   44    4  111  113   73   82  140  142  102
  168  170  179   41   43    3   12  119  121   81   90  141  101  110
  169  178  187   49    2   11   20  120  129   89   98  100  109  118
   30   39   48  148  157  166  175   79   88  146   99   59   68   77
   38   47    7  156  165  174  176   87   96  105  107   67   76   78
   46    6    8  164  173  182  184   95   55  106  115   75   84   86
  152  161  163   25   34   36  192   54   63  114  123   83   85   94
   13   15   24  180  189  191  151   62   64  122  131   91   93   53
   21   23   32  188  190  150  159   70   72  130  139   92   52   61
   22   31   40  196  149  158  167   71   80  138  147   51   60   69
*/

查看评论

Codevs 多米诺+覆盖题解

上一篇写了二分图匹配的匈牙利算法这篇当然是例题辣! 多米诺题目描述 Description 一个矩形可以划分成M*N个小正方形,其...
  • LOI__DiJiang
  • LOI__DiJiang
  • 2015-10-30 08:42:13
  • 1147

多米诺牌的完美覆盖

http://www.charlesgao.com/?p=60 从古至今,“不可能”似乎都是被人们批判的。因为随着时代的发展,很多我们认为不可能的事情都最终被证实是可能的。但作为一门严密的科学,数学...
  • Rauber_Hotzenplotz
  • Rauber_Hotzenplotz
  • 2011-12-20 10:45:13
  • 1775

棋盘的完美覆盖(多米诺骨牌完美覆盖)&&幻方(魔方阵)

棋盘的完美覆盖: 一张8行8列的棋盘一共有64个方格,用一些形状相同的多米诺骨牌覆盖,每一张覆盖相邻的两个方格,没有相互重叠,能用32张这样的多米诺骨牌完全覆盖整张棋盘称为多米诺骨牌完美覆盖或者盖瓦。...
  • theArcticOcean
  • theArcticOcean
  • 2015-07-01 09:22:47
  • 3372

棋盘的完美覆盖问题,c++代码实现

#include "stdafx.h" #include #include using namespace std; int tile=0; int *(*board) = NULL...
  • wangyaninglm
  • wangyaninglm
  • 2013-10-19 22:37:53
  • 2391

OpenJudge1665 完美覆盖

题目:http://noi.openjudge.cn/ch0405/1665/ 分析:完整的2*2矩形有3种拼法,所以f[n]+=3*f[n-2]。 当突出两块时:突出的两块时上侧两个:发现往后拼...
  • jerry99s
  • jerry99s
  • 2015-11-04 10:39:01
  • 1116

poj 2663:完美覆盖

解题思路: 递推
  • u010663294
  • u010663294
  • 2014-06-26 16:23:59
  • 999

递归-完美覆盖(算法基础 第3周)

递归-完美覆盖问题描述: 分析: 1. 原题出处POJ:http://cxsjsxmooc.openjudge.cn/hdxw11/A/ 2. 网上大都是这样的思路:http://...
  • NNNNNNNNNNNNY
  • NNNNNNNNNNNNY
  • 2016-06-06 16:05:02
  • 1080

[组合数学]关于一类棋盘的完美覆盖问题

这篇文章主要讲不规则和规则棋盘能否被1*2骨牌完美覆盖的问题 今天学了一点新的姿势,本人蒟蒻,神犇们看完不要D我先来看一个经典的问题:8*8的棋盘是否能被1*2的骨牌覆盖? 答案是肯定的,我们只要随便...
  • qq_15412011
  • qq_15412011
  • 2017-04-09 22:34:16
  • 546

b牌棋盘完美覆盖

考虑一个普通的国际象棋棋盘,它被分成8*8(8行8列)的64个正方形。设有形状一样的多米诺骨牌,每张牌恰好覆盖棋盘上相邻的两个方格(即1*2的骨牌)。那么能否把32个这样的1*2骨牌放到棋盘上,使得任...
  • wo17fang
  • wo17fang
  • 2015-08-18 16:37:10
  • 1051

OpenJudge-2663:完美覆盖

描述一张普通的国际象棋棋盘,它被分成 8 乘 8 (8 行 8 列) 的 64 个方格。设有形状一样的多米诺牌,每张牌恰好覆盖棋盘上相邻的两个方格,即一张多米诺牌是一张 1 行 2 列或者 2 行 1...
  • ACMer_hades
  • ACMer_hades
  • 2016-04-05 20:48:08
  • 975
    个人资料
    持之以恒
    等级:
    访问量: 37万+
    积分: 9426
    排名: 2418
    我的链接
    最新评论