算法系列之分治算法(棋盘问题)

分治算法(官方解释):

当我们求解某些问题时,由于这些问题要处理的数据相当多,或求解过程相当复杂,使得直接求解法在时间上相当长,或者根本无法直接求出。对于这类问题,我们往往先把它分解成几个子问题,找到求出这几个子问题的解法后,再找到合适的方法,把它们组合成求整个问题的解法。如果这些子问题还较大,难以解决,可以再把它们分成几个更小的子问题,以此类推,直至可以直接求出解为止。这就是分治策略的基本思想。

分治算法(自我理解)

其实就是讲很大的计算数据一步步分解到最小,过程中当然少不了我们之前学到的递归算法,还借鉴到二分法的算法思想,通过递归,将一个大问题分解成两个小问题,再将两个小问题分解成四个更小的问题,直到分解到很简单就能解决的问题,进而依次返回,求出最原始的大问题的解。

棋盘问题:

在一个2^k×2^k (k≥0)个方格组成的棋盘中,恰有一个方格与其他方格不同,称该方格为特殊方格。显然,特殊方格在棋盘中可能出现的位置有4^k种,因而有4^k种不同的棋盘,图4.10(a)所示是k=2时16种棋盘中的一个。棋盘覆盖问题(chess cover problem)要求用图4.10(b)所示的4种不同形状的L型骨牌覆盖给定棋盘上除特殊方格以外的所有方格,且任何2个L型骨牌不得重叠覆盖。

思路:

这个题的思路直到想到这一点我们就很快能编程出来,但是如果想不到,就很难了~

我们把2^k×2^k的方格逐渐分解,(以8*8为例)讲解一下,初始棋盘是8*8的,我们将长和宽都一分为2,这样就将棋盘分割成四个部分了,也就是每个都是4*4的棋盘,之后再将每个4*4的棋盘分解成4个2*2的棋盘,再将2*2的棋盘分解成4个1*1的方格了,然后逐步返回,当然,题目中说到有一个特殊的方格,这就需要写一个递归函数去寻找这个特殊方格,既然每个递归的过程都把原来的棋盘分解成4个小棋盘,那么就分别对左上、左下、右上、右下的棋盘进行判断是否有特殊方格,如果有,就将该部分继续递归分解,直到找到这个特殊方格的位置。

如果特殊方格没在这个范围内,就将这个范围靠近员棋盘中心的那个方格设定为特殊方格(见图b),这样也就有了特殊方格,我们也知道他的位置,就可以通过递归进行调用它,知道分解到最小单位的棋盘。

源代码:

package 分治算法;

public class 棋盘覆盖 {
public static int tile = 1;//表示L形骨牌的编号
public int [][]board=new int[4][4];//表示4*4的棋盘
//处理带有特殊棋子的棋盘,tr、tc表示棋盘的入口即左上角的序列数,dr、dc代表特殊棋子的
//位置(序列号),size代表棋盘的行列数
public void chessboard(int tr,int tc,int dr,int dc,int size){
if(size==1)return;
int t=tile++;
System.out.println(t);
int s = size/2;//每次划大棋盘为一半的子棋盘
//要处理带有特殊旗子的棋盘,需要先处理左上角的棋盘
if(dr
chessboard(tr,tc,dr,dc,s);//处理有特殊棋子的左上角棋盘
}else{ //处理无特殊棋子的左上角子棋盘
board[tr+s-1][tc+s-1] = t; //设左上角棋盘的右下角为特殊棋子用t形的骨牌覆盖
//由于骨牌骨牌有三种,当处理过程中同一级设置的特殊棋子用相同的骨牌覆盖
chessboard(tr,tc,tr+s-1,tc+s-1,s);
}

//第二步处理右上角棋盘
if(dr=tc+s){//右上角棋盘有特殊棋子
chessboard(tr,tc+s,dr,dc,s);//处理有特殊棋子的右上角棋盘
}
else{ //处理无特殊棋子的右上角棋盘
board[tr+s-1][tr+s]=t;//设右上角棋盘的左下角为特殊棋子,用t形的骨牌覆盖
//由于骨牌有三种,当处理过程中同一级设置的特殊棋子用相同的骨牌覆盖
chessboard(tr,tc+s,tr+s-1,tc+s,s);
}

//第三种处理左下角的棋盘
if(dr>=tr+s&&dc
chessboard(tr+s,tc,dr,dc,s);//处理有特殊棋子的左下角子棋盘
}
else{//处理没有左下角的子棋盘
board[tr+s][tc+s-1]=t;//设左下角的右上角为特殊棋子,用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{//处理没有特殊棋子的右下角
board[tr+s][tc+s] = t;//设右下角的左上角为特殊棋子,用t形的骨牌覆盖
//由于骨牌有三种,当处理过程中同一级设置的特殊棋子用相同的骨牌覆盖
chessboard(tr+s,tc+s,tr+s,tc+s,s);
}
}
public static void main(String[] args) {
棋盘覆盖 c=new 棋盘覆盖();
c.chessboard(0, 0, 1, 1, 4);
for(int i=0;i<4;i++){
for(int j=0;j<4;j++){
System.out.print(c.board[i][j]+" ");
}
System.out.println("");
}
}

}

猜你喜欢

转载自blog.csdn.net/qq_38691107/article/details/86063402