关闭

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

标签: 数学
3010人阅读 评论(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
*/

0
0
查看评论
发表评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场

b牌棋盘完美覆盖

考虑一个普通的国际象棋棋盘,它被分成8*8(8行8列)的64个正方形。设有形状一样的多米诺骨牌,每张牌恰好覆盖棋盘上相邻的两个方格(即1*2的骨牌)。那么能否把32个这样的1*2骨牌放到棋盘上,使得任何两张牌均不重叠,每张多米诺骨牌覆盖两个方格,并且棋盘上所有的方格都被覆盖住?我们把这样一种排列称为...
  • wo17fang
  • wo17fang
  • 2015-08-18 16:37
  • 885

用1×2骨牌覆盖n×m棋盘,有多少种方法

传送门1:UVA 11270 Tiling Dominoes #include using namespace std; const int maxn=1<<12; long long dp[2][maxn]; int cur,n,m; void add(int a,int b){ ...
  • XerxesSimon
  • XerxesSimon
  • 2017-04-25 19:04
  • 383

算法系列(一):分治策略--棋盘覆盖

算法系列(一):棋盘覆盖 一、分析 问题描述:   图1-1 k=2时的一个特殊棋盘 在一个 2^k * 2^k 个方格组成的棋盘中,若恰有一个方格与其它方格不同,则称该方格为一特殊方格,且称该棋盘为一特殊棋盘。显然特殊方格在棋盘上出现的位置有 4^k 种情形。因而对任何 k>=...
  • qq_22145801
  • qq_22145801
  • 2016-11-10 10:54
  • 404

C#图形化界面--L型骨牌

C#图形化界面实现L型骨牌的动态演示
  • JackHall
  • JackHall
  • 2015-06-17 23:31
  • 813

分治——棋盘覆盖

http://prayer.hustoj.com/problem.php?id=1350 题目描述 在一个2^k * 2^k个方格组成的棋盘中,若恰有一个方格与其它方格不同,则称该方格为一特殊方格,称改棋盘为一特殊棋盘。显然特殊方格在棋盘上出现的位置有4^k种情形。因而对任何k>=0,有4...
  • largecub233
  • largecub233
  • 2017-06-08 10:58
  • 126

骨牌覆盖问题

骨牌覆盖问题,就是用  1x2 大小的骨牌,铺设一个给定大小的一个矩形区域,要求必须铺满,且不可以超出边界。问总的铺设方案数位多少?    这一类问题就是骨牌覆盖问题。 不同规模的数据有不同的方法。       下...
  • WR_technology
  • WR_technology
  • 2016-06-06 14:29
  • 562

分治算法--棋盘覆盖

分治算法--棋盘覆盖   问题描述 在一个2^k×2^k 个方格组成的棋盘中,恰有一个方格与其他方格不同,称该方格为一特殊方格,且称该棋盘为一特殊棋盘。在棋盘覆盖问题中,要用图示的4种不同形态的L型骨牌覆盖给定的特殊棋盘上除特殊方格以外的所有方格,且任何2个L型骨牌不得...
  • yuebao1991
  • yuebao1991
  • 2016-01-07 17:21
  • 872

HIHO #1162 : 骨牌覆盖问题·三

题目链接这题和之前的一个 状态压缩二,是很类似的,这道题的n比较大,开不下数组,无法使用之前的类似方法,但是由于k比较小,可以使用状态压缩,结合这道题目的前2个版本,考虑使用矩阵快速幂进行计算,关键是计算出状态转移的矩阵M,使用dfs,跑出状态转移矩阵 用二进制表示状态, 上一行的状态用y表示 ...
  • u013167299
  • u013167299
  • 2016-08-18 15:41
  • 205

poj 2411 骨牌覆盖问题 状压dp

题目:点击打开链接 题意:用1*2 的矩形通过组合拼成大矩形,求拼成指定的大矩形有几种拼法 分析: 这题的关键在于什么状态是合法的,可以这样想,用1表示有骨牌覆盖,用0表示空着。在覆盖第i行的时候,那么如果覆盖的状态是合法的,覆盖完后第i-1行必须没有空格了(全是1111),所以...
  • loveyou11111111
  • loveyou11111111
  • 2016-02-27 00:04
  • 490

分治算法-残缺棋盘

残缺棋盘是一个2^k*2^个方格的棋盘,其中恰有1个方格残缺。图中给出,其中残缺部分用阴影表示。 这样的棋盘称为"三格板",残缺棋盘问题就是用这四种三格板覆盖更大的残缺棋盘。再次覆盖中要求: (1)两个三格板不能重复。 (2)三格板不能覆盖残缺棋盘方格,但必须覆盖到...
  • gzj_1101
  • gzj_1101
  • 2015-10-24 19:06
  • 1708
    个人资料
    • 访问:331307次
    • 积分:8856
    • 等级:
    • 排名:第2517名
    • 原创:575篇
    • 转载:13篇
    • 译文:0篇
    • 评论:36条
    我的链接
    最新评论