作者 严华云
单位 湖州师范学院
在一个2k∗2k(k为正整数,k<=10,length=2k)个方格组成的棋盘中,恰有一个方格与其他方格不同,称该方格为一特殊方格(其坐标为a,b,分别代表行坐标号和列坐标号),以及有四种L型骨牌(如下图)。求用若干块这种L型骨牌实现除该特殊点棋盘的全覆盖。(本题要求采用分治算法做)
输入格式:
输入三个数,分别是a,b,length.
输出格式:
输出整个棋盘。其中特殊方格填为0,然后铺棋盘的顺序为:先铺四个子棋盘交界的部分,然后递归的对每个子棋盘按照左上,右上,右下,左下的顺时针顺序铺满棋盘。每一块骨牌中三个方格数字相同,按照顺序标号,即第一块骨牌全标为1,第二块骨牌全标为2,...,以此类推。输出的每个数占4个场宽,右对齐。
输入样例:
1 1 4
表示:特殊格子为(1,1),棋盘有4行4列。
输出样例:
0 2 3 3
2 2 1 3
5 1 1 4
5 5 4 4
提示:先铺三个1,再铺三个2,...,最后铺三个5(即先处理子问题交界的地方,再处理左上,右上,右下,左下的子问题).
AC代码:
#include<bits/stdc++.h>
using namespace std;
int mp[1050][1050];
int a, b, length;
int cnt = 1;
int posc(int x, int y, int len,int mx,int my)//按照左上,右上,右下,左下的顺时针顺序划分区域 1,2,3,4
{
int cx = mx+len/2-1;//定位点必然点在1号区域
int cy = my+len/2-1;
if(x<=cx&&y<=cy) return 1;
if(x<=cx&&y>cy) return 2;
if(x>cx&&y>cy) return 3;
if(x>cx&&y<=cy) return 4;
}
void dis(int x, int y,int len,int mx,int my)//x,y是障碍点,len是当前维护矩阵的边长,mx,my是当前维护的矩阵的左上角一点
{ //不论是x,y还是mx,my都是之于原始矩阵(最大的那个)所给出的坐标
if (len <= 1) return;
int cx = mx+len/2-1;
int cy = my+len/2-1;//定位点是当前维护矩阵的中心点
int wh = posc(x, y, len,mx,my);
//cout << len << ":" <<"定位点:"<<cx << " " << cy <<" 障碍点"<<x<<" "<<y<<" wh:"<<wh<< endl;
if (wh == 1)
{
//1.
mp[cx][cy + 1] = cnt;
mp[cx + 1][cy + 1] = cnt;
mp[cx + 1][cy] = cnt;
cnt++;
dis(x, y, len / 2,mx+0,my+0);
dis(cx, cy + 1, len / 2,mx+0,my+len/2);
dis(cx + 1, cy + 1, len / 2,mx+len/2,my+len/2);
dis(cx + 1, cy, len / 2,mx+len/2,my+0);
}
else if (wh == 2)
{
mp[cx][cy] = cnt;
//2.
mp[cx + 1][cy + 1] = cnt;
mp[cx + 1][cy] = cnt;
cnt++;
dis(cx, cy, len / 2,mx+0,my+0);
dis(x, y, len / 2,mx+0,my+len/2);
dis(cx + 1, cy + 1, len / 2,mx+len/2,my+len/2);
dis(cx + 1, cy, len / 2,mx+len/2,my+0);
}
else if (wh == 3)
{
mp[cx][cy] = cnt;
mp[cx][cy + 1] = cnt;
//3.
mp[cx + 1][cy] = cnt;
cnt++;
dis(cx, cy, len / 2,mx+0,my+0);
dis(cx, cy + 1, len / 2,mx+0,my+len/2);
dis(x, y, len / 2,mx+len/2,my+len/2);
dis(cx + 1, cy, len / 2,mx+len/2,my+0);
}
else if (wh == 4)
{
mp[cx][cy] = cnt;
mp[cx][cy + 1] = cnt;
mp[cx + 1][cy + 1] = cnt;
//4.
cnt++;
dis(cx, cy, len / 2,mx+0,my+0);
dis(cx, cy + 1, len / 2,mx+0,my+len/2);
dis(cx + 1, cy + 1, len / 2,mx+len/2,my+len/2);
dis(x, y, len / 2,mx+len/2,my+0);
}
}
int main()
{
cin >> a >> b >> length;
for (int i = 1; i <= length; i++)
for (int j = 1; j <= length; j++)
mp[i][j] = -1;
mp[a][b] = 0;
dis(a, b,length,1,1);
for (int i = 1; i <= length; i++)
{
for (int j = 1; j <= length; j++)
{
printf("%4d",mp[i][j]);
}
cout << endl;
}
return 0;
}
把一个正方形分均分成大小一样的小正方形,按顺时针顺序标号1,2,3,4号区域
依据:判断特殊点(不可放置骨牌的点)在当前正方形的哪一号区域,然后选取缺角与之对应的L形骨牌放到正方形的中心,然后按顺序一直重复这个过程。
对选骨牌做出解释,以测试样例为例:(1,1)点位于1号区域,正好就选出了缺失一号区域这个角的骨牌。
仔细想一下,不论初始的a,b点在哪,都只对应唯一种可行的覆盖方案,即唯一解。ps反正我是画不出来:)