题目描述
相传在一个古老的阿拉伯国家里,有一座宫殿。宫殿里有个四四方方的格子迷宫,国王选择驸马的方法非常特殊,也非常简单:公主就站在其中一个方格子上,只要谁能用地毯将除公主站立的地方外的所有地方盖上,美丽漂亮聪慧的公主就是他的人了。公主这一个方格不能用地毯盖住,毯子的形状有所规定,只能有四种选择(如图):
并且每一方格只能用一层地毯,迷宫的大小为
2
k
×
2
k
2^k\times 2^k
2k×2k 的方形。当然,也不能让公主无限制的在那儿等,对吧?由于你使用的是计算机,所以实现时间为
1
1
1s。
输入格式
输入文件共
2
2
2 行。
第一行:
k
k
k,即给定被填补迷宫的大小为
2
k
×
2
k
2^k\times 2^k
2k×2k
(
0
<
k
≤
10
(0\lt k\leq10
(0<k≤10);
第二行:
x
,
y
x,y
x,y,即给出公主所在方格的坐标(
x
x
x 为行坐标,
y
y
y 为列坐标),
x
x
x 和
y
y
y 之间有一个空格隔开。
输出格式
将迷宫填补完整的方案:每一补(行)为
x
y
c
x\ y\ c
x y c(
x
,
y
x,y
x,y为毯子拐角的行坐标和列坐标,
c
c
c 为使用毯子的形状,具体见上面的图,毯子形状分别用
1
,
2
,
3
,
4
1,2,3,4
1,2,3,4 表示,
x
,
y
,
c
x,y,c
x,y,c之间用一个空格隔开)。
算法思想(分治)
题目求的是在一个 2 k × 2 k 2^k\times 2^k 2k×2k的迷宫中,使用4种地毯覆盖除公主之外的所有位置,输出地毯放置的位置和地毯类型。
- 先看最简单的情况,当
k
=
1
k=1
k=1时,即迷宫大小为
2
×
2
2\times2
2×2,公主所在位置有下面4种情况,用一张地毯就可以覆盖其余位置。
- 当
k
=
2
k=2
k=2时,情况稍微复杂一些,但可以将它看作由
4
4
4个
2
×
2
2\times2
2×2的迷宫组成的(如下图所示),那么公主必然在其中一个里,因此公主所在位置仍有4种情况。
这里我们假设公主在左上角的迷宫里,那么此时只需要在迷宫中间铺上一块地毯,将缺口面向公主所在迷宫(这里用的是1号地毯),这样就能保证每个小迷宫中都存在一个缺口,可以再使用4块地毯进行覆盖。
- 当 k k k更大时,我们仍旧可以采用上述策略,将迷宫分成 4 4 4个 2 k − 1 × 2 k − 1 2^{k-1}\times2^{k-1} 2k−1×2k−1的小迷宫,根据公主所在位置,在迷宫中间放置一块地毯,保证每个小迷宫都有一个缺口,然后使用相同的方法去处理4个小迷宫。
这种将一个复杂问题,分解成几个性质相同、规模更小的子问题,然后使用类似的思路去处理每个子问题的方法就是分治算法。
分治算法的基本思想是将一个规模为N的问题分解为K个规模较小的子问题,这些子问题相互独立且与原问题性质相同。求出子问题的解,就可得到原问题的解
算法实现
处理一个大小为 n × n n\times n n×n的迷宫,其左上角的坐标为 ( a , b ) (a,b) (a,b),此时公主所在为位置为 ( x , y ) (x,y) (x,y):
- 如果 n = 1 n = 1 n=1,无需处理
- 将迷宫分成 4 4 4个大小为 n 2 × n 2 \frac{n}{2}\times\frac{n}{2} 2n×2n的小迷宫
- 判断公主所在位置
- 选用对应地毯进行覆盖(该地毯的缺口指向公主所在的方格)
- 递归处理每个小迷宫
代码实现
#include <iostream>
using namespace std;
//从左上角(a,b)开始处理大小为n×n的迷宫,(x,y)为公主或者已覆盖的位置
void dfs(int a, int b, int x, int y, int n)
{
if(n == 1) return;
n = n / 2;
if(x <= a + n - 1 && y <= b + n - 1) //公主或者已覆盖的位置在左上角,使用1号地毯
{
printf("%d %d 1\n", a + n, b + n);
dfs(a, b, x, y, n); //公主位置不变
dfs(a, b + n, a + n - 1, b + n, n);
dfs(a + n, b, a + n, b + n - 1, n);
dfs(a + n, b + n, a + n, b + n, n);
}
else if(x <= a + n - 1 && y >= b + n) //公主或者已覆盖的位置在右上角,使用2号地毯
{
printf("%d %d 2\n", a + n, b + n - 1);
//分治,分成4个更小的部分递归处理
dfs(a, b, a + n - 1, b + n - 1, n);
dfs(a, b + n, x, y, n); //公主位置不变
dfs(a + n, b, a + n, b + n - 1, n);
dfs(a + n, b + n, a + n, b + n, n);
}
else if(x >= a + n && y <= b + n - 1) //公主或者已覆盖的位置在左下角,使用3号地毯
{
printf("%d %d 3\n", a + n - 1, b + n);
dfs(a, b, a + n - 1, b + n - 1, n);
dfs(a, b + n, a + n - 1, b + n, n);
dfs(a + n, b, x, y, n); //公主位置不变
dfs(a + n, b + n, a + n, b + n, n);
}
else //公主或者已覆盖的位置在右下角,使用4号地毯
{
printf("%d %d 4\n", a + n - 1, b + n - 1);
dfs(a, b, a + n - 1, b + n - 1, n);
dfs(a, b + n, a + n - 1, b + n, n);
dfs(a + n, b, a + n, b + n - 1, n);
dfs(a + n, b + n, x, y, n); //公主位置不变
}
}
int main()
{
int x, y, k;
scanf("%d%d%d", &k, &x, &y);
int n = 1 << k; //迷宫大小
dfs(1, 1, x, y, n);
return 0;
}