這是我CSDN博客上第100篇原創博文,之前是計劃寫一篇關於Android源碼分析的博文,但是Android源碼還在閱讀中,目前還沒有較好的體會要分享。今天在做一道算法題,許久沒寫,有點生疏了。
題目描述如下:
在一個2^k×2^k (k≥0)個方格組成的棋盤中,恰有一個方格與其他方格不同,稱該方格爲特殊方格。顯然,特殊方格在棋盤中可能出現的位置有4^k種,因而有4^k種不同的棋盤,圖(a)所示是k=2時16種棋盤中的一個。棋盤覆蓋問題(chess
cover problem)要求用圖(b)所示的4種不同形狀的L型骨牌覆蓋給定棋盤上除特殊方格以外的所有方格,且任何2個L型骨牌不得重疊覆蓋。
我嘗試了兩種實現方法。第一種是暴力地遍歷,很顯然,這中方法效率是極低的同時也是比較麻煩的。遍歷的策略比較重要,不能重複也不能遺漏。我寫完後測試,圖稍微大一點就直接爆棧,還不僅僅是效率低的問題。遞歸的層次深,明顯喫不消。
然後我嘗試了第二種方法,分治&遞歸。這也是大部分人的解法,效率自然是數量級的提升。
大體分析如下:
1.分治首先自然是要進行劃分。 我將棋盤橫豎對切分爲四塊。這樣就分出一塊有一個特殊方格的和三個沒有特殊方格的
2.進行依次劃分後,接下來是遞歸。遞歸的前提是子問題規模較父問題小但是形式上得一樣。從第一步可以知道:
有一塊是有一個特殊方格的。這個特殊的方格明顯是不能“喫掉”的。所以我將另外三個方格也給添加一個特殊方 格。
例如:
本來初始棋盤是這樣的(紅色爲特殊方塊):
然後我進行劃分後給其他三塊沒有特殊方塊的添加上“特殊方塊”。因爲題目中要求,要用“L”形骨牌進行覆蓋,因此
我只能在它們的連接處添加。
添加後如下:
這就進行了第一次劃分。
接下來就按照同樣的方法對劃分後的字塊繼續劃分。
就畫這麼多了.....
這樣代碼實現也就簡單了
直接上代碼:
/*
Author:MummyDing
Date:18/10/2015
Algorithm:ChessBoard Coverage
*/
#include<iostream>
#include<stdio.h>
#define N 500
using namespace std;
int chess[N][N]={0};
int n;
int dir[4][3][2]={
{{0,1},{1,0},{1,1}},{{0,-1},{1,-1},{1,0}},
{{-1,0},{-1,1},{0,1}},{{-1,-1},{-1,0},{0,-1}}
};
void print(){
for(int i=0;i<n;i++)
for(int j=0;j<n;j++)
printf(j== n-1 ? "%d\n":"%d ",chess[i][j]);
}
int calcType(int sx,int sy,int halfX,int halfY){
int type = 0;
if(sx > halfX) type+=2;
if(sy > halfY) type++;
return type;
}
void getXY(int &px,int &py,int type){
if(type == 1) py++;
else if(type==2)px++;
else if(type==3)px++,py++;
}
void fillBoard(int x,int y,int sx,int sy,int width){
if(width == 1) return;
int midX = width/2 + x -1;
int midY = width/2 + y -1;
int type = calcType(sx,sy,midX,midY);
int px = midX, py = midY;
getXY(px,py,type);
for(int i=0;i<3;i++){
int tmpX = px+dir[type][i][0];
int tmpY = py+dir[type][i][1];
chess[tmpX][tmpY] = type+1;
}
if(width == 2) return;
for(int i =0 ;i<4;i++){
if(i==0){
if(i==type) fillBoard(x,y,sx,sy,width/2);
else fillBoard(x,y,midX,midY,width/2);
}else if(i==1){
if(i==type) fillBoard(x,width/2+y,sx,sy,width/2);
else fillBoard(x,width/2+y,midX,midY+1,width/2);
}else if(i==2){
if(i==type) fillBoard(width/2+x,y,sx,sy,width/2);
else fillBoard(width/2+x,y,midX+1,midY,width/2);
}else{
if(i==type) fillBoard(width/2+x,width/2+y,sx,sy,width/2);
else fillBoard(width/2+x,width/2+y,midX+1,midY+1,width/2);
}
}
}
int main(){
cout<<"Input the width"<<endl;
cin>>n;
cout<<"Input x and y:"<<endl;
int x,y;
cin>> x>>y;
x--,y--;
chess[x][y]=5;
fillBoard(0,0,x,y,n);
print();
return 0;
}
【轉載請註明出處】
Author: MummyDing
出處:http://blog.csdn.net/mummyding/