一、分治的基本思想
將一個難以直接解決的大問題,分割成一些規模較小的相同問題,以便各個擊破,分而治之。
對於一個規模為 n 的問題,若問題可以容易地解決,則直接解決,否則將其分解為 k 個規模較小的子問題,這些子問題互相獨立且與原問題形式相同,遞歸地解這些子問題,然后將各子問題的解合並得到原問題的解。
二、用分治法求解問題的主要步驟
1、分解:將原問題分解為若干規模較小、相互獨立、與原問題形式相同的子問題;
2、解決:若子問題規模較小而容易被解決則直接解決,否則,遞歸地解各個子問題;
3、合並:將各子問題的解合並得到原問題的解。
三、分治法實例
1、棋盤覆蓋
在一個 2k * 2k 個方格組成的棋盤中,有一個方格與其它的不同,若使用以下四種 L 型骨牌覆蓋除這個特殊方格的其它方格,如何覆蓋。四個 L 型骨牌如下圖:
圖1.1 L型骨牌
棋盤中的特殊方格如圖:

圖1.2 存在特殊方格的棋盤
覆蓋完成后的棋盤:

圖1.3 覆蓋完成的棋盤
1 #include<iostream> 2 using namespace std; 3 4 int tile = 0; 5 int Board[4][4]; //棋盤 6 7 /* 8 tr:棋盤左上角方格的行號 9 tc:棋盤左上角方格的列號 10 dr:特殊方格所在的行號 11 dc:特殊方格所在的列號 12 size:棋盤的規格(size * size) 13 */ 14 void ChessBoard(int tr,int tc , int dr, int dc, int size) 15 { 16 if(size == 1) return; 17 int t =tile++, //L型骨牌號 18 s = size/2; //分割棋盤 19 //覆蓋左上角子棋盤 20 if(dr < tr+s && dc < tc+s) 21 //特殊方格在此棋盤中 22 ChessBoard(tr,tc,dr,dc,s); 23 else 24 { //此棋盤中無特殊方格 25 //用t號L型骨牌覆蓋右下角 26 Board[tr+s-1][tc+s-1] = t; 27 //覆蓋其余方格 28 ChessBoard(tr,tc,dr,dc,s); 29 } 30 31 //覆蓋右上角子棋盤 32 if(dr < tr+s && dc >= tc+s) 33 //特殊方格在此棋盤中 34 ChessBoard(tr,tc+s,dr,dc,s); 35 else 36 { //此棋盤中無特殊方格 37 //用t號L型骨牌覆蓋左下角 38 Board[tr+s-1][tc+s] = t; 39 //覆蓋其余方格 40 ChessBoard(tr,tc+s,tr+s-1,tc+s,s); 41 } 42 43 //覆蓋左下角子棋盤 44 if(dr >= tr+s && dc < tc+s) 45 //特殊方格在此棋盤中 46 ChessBoard(tr+s,tc,dr,dc,s); 47 else 48 { //此棋盤中無特殊方格 49 //用t號L型骨牌覆蓋右上角 50 Board[tr+s][tc+s-1] = t; 51 //覆蓋其余方格 52 ChessBoard(tr+s,tc,tr+s,tc+s-1,s); 53 } 54 55 //覆蓋右下角子棋盤 56 if(dr >= tr+s && dc >= tc+s) 57 //特殊方格在此棋盤中 58 ChessBoard(tr+s,tc+s,dr,dc,s); 59 else 60 { //此棋盤中無特殊方格 61 //用t號L型骨牌覆蓋左上角 62 Board[tr+s][tc+s] = t; 63 //覆蓋其余方格 64 ChessBoard(tr+s,tc+s,tr+s,tc+s,s); 65 } 66 67 } 68 69 int main() 70 { 71 ChessBoard(0 , 0 , 1 , 3 , 4); 72 //輸出覆蓋完成后的棋盤 73 for(int i = 0 ; i < 4; i++) 74 { 75 for(int j = 0 ; j < 4; j++) 76 { 77 cout<<Board[i][j]; 78 } 79 cout<<endl; 80 } 81 return 0; 82 }
2、循環賽日程表
設有 n = 2k 個運動員要進行網球循環賽。現要設計一個滿足以下要求的比賽日程表:
(1)每個選手必須與其他n-1個選手各賽一次;
(2)每個選手一天只能參賽一次;
(3)循環賽在n-1天內結束。
請按此要求將比賽日程表設計成有 n 行和 n-1 列的一個表。在表中的第 i 行,第 j 列處填入第 i 個選手在第 j 天所遇到的選手。其中 1 ≤ i ≤ n,1 ≤ j ≤ n-1。8 個選手的比賽日程表如下圖:
1 #include<iostream> 2 using namespace std; 3 4 int a[100][100]; 5 int n; //選手的個數 6 7 /* 8 tox:目標數組的行號 9 toy:目標數組的列號 10 fromx:源數組的行號 11 fromy:源數組的列號 12 r:數組的大小為 r*r 13 */ 14 void Copy(int tox, int toy, int fromx, int fromy, int r) 15 { 16 for(int i = 0; i < r; i++) 17 for(int j = 0; j < r; j++) 18 a[tox+i][toy+j] = a[fromx+i][fromy+j]; 19 } 20 21 void Table(int k) 22 { 23 n = 1 << k; 24 //構造正方形表格的第一行數據 25 for(int i = 0; i < n; i++) 26 a[0][i] = i + 1; 27 //采用分治算法,構造整個循環賽日程表 28 for(int r = 1; r < n; r <<= 1) 29 for(int i = 0; i < n; i += 2*r) 30 { 31 Copy(r, r + i, 0, i, r); //左上角復制到右下角 32 Copy(r, i, 0, r + i, r); //右上角復制到左下角 33 } 34 } 35 36 37 int main() 38 { 39 int k; 40 cout<<"請輸入k的值:"; 41 cin>>k; 42 43 Table(k); 44 45 for(int i = 0; i < n; i++) 46 { 47 for(int j = 0; j < n; j++) 48 { 49 cout<< a[i][j] << " "; 50 } 51 cout<<endl; 52 } 53 return 0; 54 }