棋盘覆盖问题
今天来讲讲棋盘覆盖,其实是算法课讲到了这一问题,也顺便复习一下。
棋盘覆盖问题其实就是将含有特殊方格且具有一定规格的棋盘用各种L型方格覆盖,这个问题用分治和递归解决起来比较简单。下面就是一个例子的解决答案。(棋盘的大小为4*4,特殊方格为(1,1))
下面详细讲一下棋盘覆盖问题的具体细节。此问题的棋盘具有一定的特殊性,为2的n次方(因为只有这样才可以保证可以完美解决问题)。特殊方格的位置不定,只要在棋盘的内部。在这里除去特殊方格,其他的方格要用不可以间断的L型方格覆盖。L型方格的形状不固定(只要是L型)。上图还是一个理解的例子。相同数字为一个L型方格。
下面讲一下具体的解决思路。递归在前面已经讲过,不再叙述。这里讲一下思路。将棋盘分割成4个子棋盘,将特殊方格所在的子棋盘单独处理。先讲一讲其他的三个子棋盘。将其他的三个子棋盘的方位对角的方格标记为特殊方格,在用递归继续求解各个子棋盘的解决答案。如上图,0为特殊方格,将棋盘分为四个子棋盘。分别为
左上角 右上角 左下角 右下角
将特殊方格不在的其他三个子棋盘的对角方格标记为特殊棋盘。如右上角的子棋盘就是该棋盘的左下角的方格1为特殊方格。这样就保证棋盘的覆盖都是L型方格。子棋盘标记好特殊方格后直接递归,交给下一步去计算子棋盘的解。特殊方格所在的子棋盘不用标记,直接递归。这样直到当前的棋盘为1时,跳出递归,解决问题。因为本人的叙述可能有些问题,要是还不懂的话可以看一下别人对问题的叙述。。。
下面讲一讲算法的具体实现,因为用到递归,所以递归的主体和递归的边界比较重要。递归主体主要由四个if判断语句构成,分别代表将棋盘分割的四个子棋盘。if语句要先判断特殊方格的位置,在将下一步的特殊方格标记。用递归交给下一步。这里要注意,因为要与下一步区别开来,但是一个特殊方格的位置参数显然不够,这里还要在传一个当前子棋盘的左上角的方格的坐标,所以就有了四个参数,同时因为棋盘要分割,所以还要传一个当前棋盘的大小。所以,总共需要五个参数。函数的主体已经解决了,下面说一说递归的边界,因为担心边界的问题,所以这里直接将棋盘的大小设置为1时,递归结束。(也可以将棋盘的大小递归边界设置为2,但是要考虑一些细节问题,这里不再叙述)好了,算法的递归完成,剩下的就是一些细节问题。比如讲特殊方格标记。。。这里不再叙述,都在代码里了。下面就是代码。
import java.util.Scanner; public class demo { static int title=1; static int a[][]=new int[100][100]; //tr,tc分别为当前棋盘的行号和列号。dr,dc为特殊方格的行号和列号。size为棋盘的大小。 public static void qipanfugai(int tr,int tc,int dr,int dc,int size) { //递归边界 if(size==1)//这里的size为上一层的s,当s为2时还要递归一次。再递归一次的时候t会被在加一次 { return; } int t=title++;//覆盖棋盘的数字 //System.out.println(t+"t被加了一次"); int s=size/2;//s为将棋盘分割 //递归主体 //左上角棋盘覆盖 if(dr<tr+s&&dc<tc+s){//特殊方格在左上角,下面也是一样 qipanfugai(tr, tc, dr, dc, s); //System.out.println("哈哈"); }else{ a[tr+s-1][tc+s-1]=t;//用t覆盖右下角的方格 qipanfugai(tr, tc, tr+s-1, tc+s-1, s);//递归给下一步,特殊方格的位置发生了变化 } //右上角棋盘覆盖 if(dr<tr+s&&dc>=tc+s){ qipanfugai(tr, tc+s, dr, dc, s); }else{ a[tr+s-1][tc+s]=t; qipanfugai(tr, tc+s, tr+s-1, tc+s, s); } //左下角棋盘覆盖 if(dr>=tr+s&&dc<tc+s){ qipanfugai(tr+s, tc, dr, dc, s); }else{ a[tr+s][tc+s-1]=t; qipanfugai(tr+s, tc, tr+s, tc+s-1, s); } //右下角棋盘覆盖 if(dr>=tr+s&&dc>=tc+s){ qipanfugai(tr+s, tc+s, dr, dc, s); }else{ a[tr+s][tc+s]=t; qipanfugai(tr+s, tc+s, tr+s, tc+s, s); } } public static void main(String args[]) { System.out.println("请输入棋盘的大小和特殊方格的位置。输入格式为“4 2 2”"); Scanner reader = new Scanner(System.in); int dr,dc,size; size=reader.nextInt(); dr=reader.nextInt(); dc=reader.nextInt(); System.out.println(); qipanfugai(0,0, dr, dc, size);//特殊方格没有动,所以一直为0 for(int i=0;i<size;i++) { for(int j=0;j<size;j++) { System.out.print(a[i][j]+" "); } System.out.println(); } } }
算法总体还是比较好理解的,都是一些细节的问题。我在一些细节问题上面卡了好久,比如要先判断棋盘的大小是否为1,在去执行下一步,要不然就会出现下面的情况。
答案也对,但是感觉怪怪的。剩下的一些问题都写在注释里了。就这样吧