【Algorithm】棋盤覆蓋問題

這是我CSDN博客上第100篇原創博文,之前是計劃寫一篇關於Android源碼分析的博文,但是Android源碼還在閱讀中,目前還沒有較好的體會要分享。今天在做一道算法題,許久沒寫,有點生疏了。

 題目描述如下:

在一個2^k×2^k (k≥0)個方格組成的棋盤中,恰有一個方格與其他方格不同,稱該方格爲特殊方格。顯然,特殊方格在棋盤中可能出現的位置有4^k種,因而有4^k種不同的棋盤,圖(a)所示是k=2時16種棋盤中的一個。棋盤覆蓋問題(chess cover problem)要求用圖(b)所示的4種不同形狀的L型骨牌覆蓋給定棋盤上除特殊方格以外的所有方格,且任何2個L型骨牌不得重疊覆蓋。



我嘗試了兩種實現方法。第一種是暴力地遍歷,很顯然,這中方法效率是極低的同時也是比較麻煩的。遍歷的策略比較重要,不能重複也不能遺漏。我寫完後測試,圖稍微大一點就直接爆棧,還不僅僅是效率低的問題。遞歸的層次深,明顯喫不消。

然後我嘗試了第二種方法,分治&遞歸。這也是大部分人的解法,效率自然是數量級的提升。

大體分析如下:

1.分治首先自然是要進行劃分。 我將棋盤橫豎對切分爲四塊。這樣就分出一塊有一個特殊方格的和三個沒有特殊方格的

2.進行依次劃分後,接下來是遞歸。遞歸的前提是子問題規模較父問題小但是形式上得一樣。從第一步可以知道:

 有一塊是有一個特殊方格的。這個特殊的方格明顯是不能“喫掉”的。所以我將另外三個方格也給添加一個特殊方          格。

例如:

本來初始棋盤是這樣的(紅色爲特殊方塊)


然後我進行劃分後給其他三塊沒有特殊方塊的添加上“特殊方塊”。因爲題目中要求,要用“L”形骨牌進行覆蓋,因此

我只能在它們的連接處添加。

添加後如下:



這就進行了第一次劃分。

接下來就按照同樣的方法對劃分後的字塊繼續劃分。

   



就畫這麼多了.....

這樣代碼實現也就簡單了

直接上代碼:


/*
Author:MummyDing
Date:18/10/2015
Algorithm:ChessBoard Coverage
*/
#include<iostream>
#include<stdio.h>
#define N 500
using namespace std;
int chess[N][N]={0};
int n;
int dir[4][3][2]={
    {{0,1},{1,0},{1,1}},{{0,-1},{1,-1},{1,0}},
    {{-1,0},{-1,1},{0,1}},{{-1,-1},{-1,0},{0,-1}}
};
void print(){
    for(int i=0;i<n;i++)
    for(int j=0;j<n;j++)
    printf(j== n-1 ? "%d\n":"%d ",chess[i][j]);
}
int calcType(int sx,int sy,int halfX,int halfY){
    int type = 0;
    if(sx > halfX) type+=2;
    if(sy > halfY) type++;
    return type;
}
void getXY(int &px,int &py,int type){
    if(type == 1) py++;
    else if(type==2)px++;
    else if(type==3)px++,py++;
}
void fillBoard(int x,int y,int sx,int sy,int width){
    if(width == 1) return;
    int midX = width/2 + x -1;
    int midY = width/2 + y -1;
    int type = calcType(sx,sy,midX,midY);
    int px = midX, py = midY;
    getXY(px,py,type);
    for(int i=0;i<3;i++){
        int tmpX = px+dir[type][i][0];
        int tmpY = py+dir[type][i][1];
        chess[tmpX][tmpY] = type+1;
    }
    if(width == 2) return;
    for(int i =0 ;i<4;i++){
        if(i==0){
            if(i==type) fillBoard(x,y,sx,sy,width/2);
            else fillBoard(x,y,midX,midY,width/2);
        }else if(i==1){
            if(i==type) fillBoard(x,width/2+y,sx,sy,width/2);
            else fillBoard(x,width/2+y,midX,midY+1,width/2);
        }else if(i==2){
            if(i==type) fillBoard(width/2+x,y,sx,sy,width/2);
            else fillBoard(width/2+x,y,midX+1,midY,width/2);
        }else{
            if(i==type) fillBoard(width/2+x,width/2+y,sx,sy,width/2);
            else fillBoard(width/2+x,width/2+y,midX+1,midY+1,width/2);
        }
    }
}
int main(){
    cout<<"Input the width"<<endl;
    cin>>n;
    cout<<"Input x and y:"<<endl;
    int x,y;
    cin>> x>>y;
    x--,y--;
    chess[x][y]=5;
    fillBoard(0,0,x,y,n);
    print();
    return 0;
}



GitHub 完整代碼: https://github.com/MummyDing/Algorithm-Design/tree/master/ChessBoard_Coverage

【轉載請註明出處】

Author: MummyDing

出處:http://blog.csdn.net/mummyding/




發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章