1. 程式人生 > >演算法1-2:棋盤覆蓋問題

演算法1-2:棋盤覆蓋問題

★問題描述:在一個2^k×2^k的方格組成的棋盤中,若恰有一個方格與其他方格不同,則稱該方格為一特殊方格,且稱該棋盤為一特殊棋盤。顯然特殊方格在棋盤上出現的位置有4^k種情形。因而對任何k≥0,有4^k種不同的特殊棋盤。在棋盤覆蓋問題中,要用L型骨牌覆蓋一個給定棋盤上除特殊方格以外的所有方格,且任何2個L型骨牌不得重複覆蓋。

★演算法設計:利用分治策略,可以設計解棋盤演算法問題的一個簡潔演算法。

★資料輸入:輸入一個K值作為棋盤的大小,之後輸入兩個值作為特殊方格的位置

★資料輸出:輸出棋盤,要求標出每個L型骨牌的序號

例:

輸入:

2        

2  2     

輸出:

2  2  3  3

2  0  1  3

4  1  1  5

4  4  5  5

首先來分析一下,在棋盤裡只有一塊特殊的方格,而且棋盤的大小也比較特殊,2的K次方,非常適合切分成一半。又因為棋盤是個方形的,所以思路可以使將棋盤分成大小相同的四份。

分支法的基本思想是一個較大的問題,將其分成n個子問題,並且n個子問題解決後能合併成原問題的解。

當我們將有特殊方格的棋盤分割成4個相同的子棋盤時,4個棋盤分成兩類:有特殊方格和沒有特殊方格。我們用到的L型骨牌剛好是三個方格的,也就是說可以用一個L型骨牌將其餘的三個沒有特殊方格的棋盤變成有特殊方格的。


之後我們便可利用遞迴的方法來對其進行賦值。

用一個全域性變數來記錄用骨牌的個數,每層的骨牌序號用一個變數來記錄,程式如下:

#include <stdio.h>
#include <stdlib.h>
int size;//用於記錄棋盤的大小
int tile=0;//用於記錄骨牌的序號
int a[128][128]={-1};
void ChessBoard(int tr,int tc,int dr,int dc,int size);
int main()
{
    int i,j,k;
    printf("請輸入K值的大小:\n");
    scanf("%d",&i);
    for(j=0,k=1;j<i;j++)
        k*=2;
    printf("輸入特殊方格位置:\n");
    scanf("%d%d",&i,&j);
    i--;j--;
    a[i][j]=0;
    ChessBoard(0,0,i,j,k);
    for(i=0;i<k;i++){
        for(j=0;j<k;j++)
            if(a[i][j]>9||a[i][j]==-1)
                printf(" %d",a[i][j]);
            else printf("  %d",a[i][j]);
        printf("\n");
    }
    return 0;
}
void ChessBoard(int tr,int tc,int dr,int dc,int
size){
    if(size==1)return;
    int t=++tile;//t用於儲存在這一層遞迴中骨牌的序號
    int s=size/2;

    if(dr<tr+s&&dc<tc+s)
        ChessBoard(tr,tc,dr,dc,s);
    else {
        a[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 {
        a[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,dr,dc,s);
    else {
        a[tr+s][tc+s-1]=t;
        ChessBoard(tr+s,tc,tr+s,tc+s-1,s);
    }
    if(dr>=tr+s&&dc>=tc+s)
        ChessBoard(tr+s,tc+s,dr,dc,s);
    else {
        a[tr+s][tc+s]=t;
        ChessBoard(tr+s,tc+s,tr+s,tc+s,s);
    }
}

本文使用的程式碼為C語言的程式碼,在和同學一起討論的過程中,發現C++中呼叫函式的括號可以用中括號,編譯時不會顯示出錯,但是執行時並不會呼叫該函式,希望在以後使用C++編程式碼時可以注意一下,程式碼的執行結果如下: