分治棋盤覆蓋

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

實現

  1. 每次都對分割後的四個小方塊進行判斷,判斷特殊方格是否在裏面。
  2. 這裏的判斷的方法是每次先記錄下整個大方塊的左上角topLeftConer
    方格的行列座標
  3. 然後再與特殊方格座標進行比較,就可以知道特殊方格是否在該塊中。
  4. 如果特殊方塊在裏面,直接遞歸下去求即可
  5. 如果不在,這根據分割的四個方塊的不同位置,把右下角、左下角、右上角或者左上角的方格標記爲特殊方塊,然後繼續遞歸。

注意: 在遞歸函數裏,還要有一個變量s來記錄邊的方格數,每次對方塊進行劃分時,邊的方格數都會減半,這個變量是爲了方便判斷特殊方格的位置。其次還要有一個變nCount來記錄L型骨牌的數量。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int nCount = 0,t=0;
int board[100][100];

// void chessBoard(int tr, int tc, int dr, int dc, int size);
void ChessBoard(int tr, int tc, int dr, int dc, int size)
{
    int s, t1; //t1表示本次覆蓋所用L型骨牌的編號
    if (size == 1)
        return;                        //棋盤只有一個方格且是特殊方格
    t1 = ++t;                          // L型骨牌編號
    s = size / 2;                      // 劃分棋盤
    if (dr < tr + s && dc < tc + s)    //特殊方格在左上角子棋盤中
        ChessBoard(tr, tc, dr, dc, s); //遞歸處理子棋盤
    else
    { //用 t1號L型骨牌覆蓋右下角,再遞歸處理子棋盤
        board[tr + s - 1][tc + s - 1] = t1;
        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
    { //用 t1號L型骨牌覆蓋左下角,再遞歸處理子棋盤
        board[tr + s - 1][tc + s] = t1;
        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
    { //用 t1號L型骨牌覆蓋右上角,再遞歸處理子棋盤
        board[tr + s][tc + s - 1] = t1;
        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
    { //用 t1號L型骨牌覆蓋左上角,再遞歸處理子棋盤
        board[tr + s][tc + s] = t1;
        ChessBoard(tr + s, tc + s, tr + s, tc + s, s);
    }
}

int main()
{
    int size, r, c, row, col;
    memset(board, 0, sizeof(board));
    scanf("%d", &size);        //方陣大小
    scanf("%d%d", &row, &col); //特殊點,座標從1開始
    ChessBoard(0, 0, row, col, size);
    for (r = 0; r < size; r++)
    {
        for (c = 0; c < size; c++)
        {
            printf("%2d ", board[r][c]);
        }
        printf("\n");
    }
    return 0;
}

參考鏈接:

  1. 棋盤覆蓋百度百科
  2. 棋盤覆蓋問題-分治法By: JoJonny

代碼思路,編輯格式不易,大家覺得還可以可以點贊、收藏、關注一下吧!
也可以到我的個人博客參觀一下,https://motongxue.gitee.io

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