演算法競賽入門經典第八章 遞迴與分治之棋盤覆蓋問題

2021-10-03 07:29:30 字數 2207 閱讀 8045

題目:有乙個2k∗

2k2^k*2^k

2k∗2

k的方格棋盤,恰有乙個方格是黑色的,其他為白色。你的任務是用包含3個方格的l型牌覆蓋所有白色方格。黑色方格不能被覆蓋,且任意乙個白色方格不能同時被兩個或更多牌覆蓋。

由於棋盤是2k∗

2k2^k*2^k

2k∗2

k的,很容易在中間橫豎各一刀劃分為4個2k−

1∗2k

−12^*2^

2k−1∗2

k−1的小棋盤,繼續劃分一直到k=1,成為2∗2

2*22∗

2的棋盤。如果k=1,且2∗2

2*22∗

2的棋盤上有乙個黑色方塊,那麼可以用一塊l牌覆蓋。

那麼其它的不含黑色方塊的區域呢?當k=2時,棋盤大小為4×4

4×44×

4,其上下左右四個區域有乙個區域有黑色方塊,另外三個沒有。那麼我們可以用一塊l牌覆蓋有黑色方塊的區域,另外三個區域採用下圖的覆蓋方式,能夠留出乙個l型的未覆蓋區域,剛好再用一塊l牌覆蓋。

這樣我們就知道遞迴的基本思路了:將棋盤劃分成四部分,如果:

左上部分沒有黑色方塊,將左上部分右下角設定為特殊方塊(將被圖中紫色l牌覆蓋);

右上部分沒有黑色方塊,將左上部分左下角設定為特殊方塊(將被圖中紫色l牌覆蓋);

左下部分沒有黑色方塊,將左上部分右上角設定為特殊方塊(將被圖中紫色l牌覆蓋);

右下部分沒有黑色方塊,將左上部分左上角設定為特殊方塊(將被圖中紫色l牌覆蓋);

每次遞迴分別檢查上下左右四部分,如果有黑色方塊則繼續遞迴,否則填充特殊方塊。將特殊方塊視為黑色方塊並再次遞迴。當棋盤為2∗2

2*22∗

2時填充完畢,當棋盤為1∗1

1*11∗

1時直接返回(base case)。注意全域性變數count和區域性變數t的使用,count的最終值同時也是使用的l牌塊數。

#include

#include

using

namespace std;

int count =1;

void

print

(vector

int>> s)

}void cover_board (vector< vector<

int>

>

&board,

int size,

int lu_r,

int lu_c,

int black_r,

int black_c)

//black_r和black_c記錄黑色方塊所在行和列。lu_x和lu_y記錄當前棋盤左上角的行和列。

if(black_r >= lu_r + n && black_c < lu_c + n)

//黑色方塊在左下角

cover_board

(board, n, lu_r + n, lu_c, black_r, black_c)

;else

if(black_r < lu_r+n && black_c >= lu_c + n)

//黑色方塊在右上角

cover_board

(board, n, lu_r, lu_c+n, black_r, black_c)

;else

if(black_r >= lu_r+n && black_c >= lu_c + n)

//黑色方塊在右下角

cover_board

(board, n, lu_r+n, lu_c+n, black_r, black_c)

;else

}int

main()

size=8,黑色方塊位於第四排第六列時輸出結果:

size=16,黑色方塊位於第四排第六列時輸出結果:

演算法競賽入門經典(第八章)

習題8 1 uva1149 11.8 include include using namespace std int main sort w 1,w n 1 l 1 r n num 0 while l r if mi w l 0 l num cout 習題8 2 uva1610 11.8 inclu...

演算法入門經典第八章學習筆記(上)

教學內容相關章節 8.1演算法分析初步 8.2再談排序與搜尋 8.3遞迴與分治 8.4貪心法 教學目標 加粗表示基本掌握 1 理解 基本操作 漸近時間複雜度的概念和大o記號的含義 2 掌握 最大連續和 問題的各種演算法及其時間複雜度分析 3 正確認識演算法分析的優點和侷限性,能正確使用分析結果 4 ...

演算法入門經典第八章學習筆記(中)

有乙個2 k 2 k個方格棋盤,恰有乙個方格是灰色的,其他為白色,你的任務是用包含3個方格的l型骨牌覆蓋所有白色方格。灰色方格不能被子覆蓋,且任意乙個白色方格不能同時被兩個或更多骨牌覆蓋。如圖8 3所示為l型骨牌 三格板 的4種旋轉方式。方法也是分治法,總牌數 4 k 1 3 劃分成下面 a 這樣,...