棋盘覆盖(C语言)
问题描述:
如何应用分治法求解棋盘覆盖问题呢?分治的技巧在于如何划分棋盘,使划分后的子棋盘的大小相同,并且每个子棋盘均包含一个特殊方格,从而将原问题分解为规模较小的棋盘覆盖问题。k>0时,可将2k×2k的棋盘划分为4个2(k-1)×2(k-1)的子棋盘,如图(a)所示。这样划分后,由于原棋盘只有一个特殊方格,所以,这4个子棋盘中只有一个子棋盘包含该特殊方格,其余3个子棋盘中没有特殊方格。为了将这3个没有特殊方格的子棋盘转化为特殊棋盘,以便采用递归方法求解,可以用一个L型骨牌覆盖这3个较小棋盘的会合处,如图(b)所示,从而将原问题转化为4个较小规模的棋盘覆盖问题。递归地使用这种划分策略,直至将棋盘分割为1×1的子棋盘。
思路:
如何应用分治法求解棋盘覆盖问题呢?分治的技巧在于如何划分棋盘,使划分后的子棋盘的大小相同,并且每个子棋盘均包含一个特殊方格,从而将原问题分解为规模较小的棋盘覆盖问题。k>0时,可将2k×2k的棋盘划分为4个2(k-1)×2(k-1)的子棋盘,这样划分后,由于原棋盘只有一个特殊方格,所以,这4个子棋盘中只有一个子棋盘包含该特殊方格,其余3个子棋盘中没有特殊方格。为了将这3个没有特殊方格的子棋盘转化为特殊棋盘,以便采用递归方法求解,可以用一个L型骨牌覆盖这3个较小棋盘的会合处,从而将原问题转化为4个较小规模的棋盘覆盖问题。递归地使用这种划分策略,直至将棋盘分割为1×1的子棋盘。——来自百度百科
下面我来说说我的理解吧:
首先,我们按照最小的模式,也就是 k=0 的时候,此时只有一个特殊方格没有三角方格需要放置,当然这种情况还是比较少的。
接下来,就是 k=1 的时候,也就是有四个方格,无论特殊方格的位置在哪,我们都可以找到一个直角方格放置。
…
接下来,就是 k 不断地递增,利用分治的思想,可以把大方格划分成小方格,划分到最后就剩下最后一个包含有特殊方格的四方格,这个时候,我们的直角方格该以哪种形式存在呢?对吧,面临的四边其实都是可以放置直角方格的。
这个时候利用分治的思想,也就是说把原有的大方个,划分成四个相对小一个阶级的方格
…
到最后就回到了递归的出口,也就是说,特殊方格分别在四方格的四个角上的情况。
#include<stdio.h>
#define n 8 //n为2^k
int tr,tc; //子棋盘的左上角第一个方格的横纵坐标
int dr,dc; //特殊方格的横纵坐标
int size;
int board[n][n];
int tile=1; //骨牌序号从1开始
void input()
{
printf("输出棋盘长度:%d
",n);
printf("请输入特殊棋盘的位置dr,dc:");
scanf("%d,%d",&dr,&dc);
board[dr][dc]=0;
}
void chess(int tr,int tc,int dr,int dc,int size)
{
if(size==1)
return;
int t=tile++;
int s=size/2;
if(dr<tr+s && dc<tc+s) //特殊方格在左上方
chess(tr,tc,dr,dc,s);
else
{
board[tr+s-1][tc+s-1]=t;
chess(tr,tc,tr+s-1,tc+s-1,s);
}
if(dr<tr+s && dc>=tc+s) //特殊方格在右上方
chess(tr,tc+s,dr,dc,s);
else
{
board[tr+s-1][tc+s]=t;
chess(tr,tc+s,tr+s-1,tc+s,s);
}
if(dr>=tr+s && dc<tc+s) //特殊方格在左下方
chess(tr+s,tc,dr,dc,s);
else
{
board[tr+s][tc+s-1]=t;
chess(tr+s,tc,tr+s,tc+s-1,s);
}
if(dr>=tr+s && dc>=tc+s) //特殊方格在右下方
chess(tr+s,tc+s,dr,dc,s);
else
{
board[tr+s][tc+s]=t;
chess(tr+s,tc+s,tr+s,tc+s,s);
}
}
void display() //输出二维数组
{
int i,j;
for(i=0;i<n;i++)
{
for(j=0;j<n;j++)
{
printf("%4d ",board[i][j]);
}
printf("
");
}
}
void main()
{
input();
chess(0,0,dr,dc,n);
display();
}
代码应该可以看明白