1. 程式人生 > >棋盤的完美覆蓋(多米諾骨牌完美覆蓋)&&幻方(魔方陣)

棋盤的完美覆蓋(多米諾骨牌完美覆蓋)&&幻方(魔方陣)

棋盤的完美覆蓋:

一張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
*/