棋盤覆蓋問題

z十一發表於2020-11-29

在一個2^k * 2k(k為正整數,k<=10,length=2k)個方格組成的棋盤中,恰有一個方格與其他方格不同,稱該方格為一特殊方格(其座標為aa,bb,分別代表行座標號和列座標號),以及有四種L型骨牌(如下圖)。求用若干塊這種L型骨牌實現除該特殊點棋盤的全覆蓋。(本題要求採用分治演算法做)

輸入格式:
輸入三個數,分別是aa,bb,length.

輸出格式:
輸出整個棋盤。其中特殊方格填為0,然後鋪棋盤的順序為:先鋪四個子棋盤交界的部分,然後遞迴的對每個子棋盤按照左上,右上,右下,左下的順時針順序鋪滿棋盤。每一塊骨牌中三個方格數字相同,按照順序標號,即第一塊骨牌全標為1,第二塊骨牌全標為2,…,以此類推。輸出的每個數佔4個場寬,右對齊。

輸入樣例:
1 1 4
表示:特殊格子為(1,1),棋盤有4行4列。

輸出樣例:
0 2 3 3
2 2 1 3
5 1 1 4
5 5 4 4
表示:先鋪三個1(一塊L型骨牌),再鋪三個2,…,最後鋪三個5.

分治的技巧在於如何劃分棋盤,使劃分後的子棋盤的大小相同,並且每個子棋盤均包含一個特殊方格,從而將原問題分解為規模較小的棋盤覆蓋問題。k>0時,可將2k×2k的棋盤劃分為4個2(k-1)×2(k-1)的子棋盤。這樣劃分後,由於原棋盤只有一個特殊方格,所以,這4個子棋盤中只有一個子棋盤包含該特殊方格,其餘3個子棋盤中沒有特殊方格。為了將這3個沒有特殊方格的子棋盤轉化為特殊棋盤,以便採用遞迴方法求解,可以用一個L型骨牌覆蓋這3個較小棋盤的會合處,從而將原問題轉化為4個較小規模的棋盤覆蓋問題。遞迴地使用這種劃分策略,直至將棋盤分割為1×1的子棋盤。

演算法設計:
(1)用一個二維陣列board[size][size]表示一個棋盤,其中,size=2^k。陣列board設為全域性變數;
(2)子棋盤由棋盤左上角的下標tr、tc和棋盤大小s表示;
(3)特殊方格用board[dr][dc]表示特殊方格,dr和dc是該特殊方格在二維陣列board中的下標;
(4) L型骨牌:一個2k×2k的棋盤中有一個特殊方格,所以,用到L型骨牌的個數為(4^k-1)/3,將所有L型骨牌從1開始連續編號,用一個全域性變數tile表示。
(5)每次判斷特殊方塊的位置,遞迴呼叫程式,並不斷新增方塊。
(6)左上的子棋盤(若不存在特殊方格)----則將該子棋盤右下角的那個方格假設為特殊方格;右上的子棋盤(若不存在特殊方格)----則將該子棋盤左下角的那個方格假設為特殊方格;左下的子棋盤(若不存在特殊方格)----則將該子棋盤右上角的那個方格假設為特殊方格;右下的子棋盤(若不存在特殊方格)----則將該子棋盤左上角的那個方格假設為特殊方格

程式碼:

#include<iostream>
using namespace std;
#define N 90
int board[N][N];
int tile=1;
void chessboard(int tr,int tc,int dr,int dc,int size)
{
    if(size==1) 
        return;
    int t=tile++;
    int s=size/2;
    if(dr<tr+s&&dc<tc+s)
        chessboard(tr,tc,dr,dc,s);
    else
    {
        board[tr+s-1][tc+s-1]=t;
        chessboard(tr,tc,tr+s-1,tc+s-1,s);
    }
    if(dr<tr+s&&dc>=tc+s)
        chessboard(tr,tc+s,dr,dc,s);
    else
    {
        board[tr+s-1][tc+s]=t;
        chessboard(tr,tc+s,tr+s-1,tc+s,s);
    }

    if(dr>=tr+s&&dc>=tc+s)
        chessboard(tr+s,tc+s,dr,dc,s);
    else
    {
        board[tr+s][tc+s]=t;
        chessboard(tr+s,tc+s,tr+s,tc+s,s);
    }    if(dr>=tr+s&&dc<tc+s)
        chessboard(tr+s,tc,dr,dc,s);
    else
    {
        board[tr+s][tc+s-1]=t;
        chessboard(tr+s,tc,tr+s,tc+s-1,s);
    }    
}
int main()
{
    int aa,bb,length;
    cin>>aa>>bb>>length;
    chessboard(1,1,aa,bb,length+1);
    int i,j;
    for(i=1;i<=length;i++)
    {
        for(j=1;j<=length;j++)
            printf("%4d",board[i][j]);
        cout<<endl;
    }
        
}

相關文章