CJOJ P1619 - 【中学高级本】地毯填补

Description

相传在一个古老的阿拉伯国家里,有一座宫殿。宫殿里有个四四方方的格子迷宫,国王选择驸马的方法非常特殊,也非常简单:公主就站在其中一个方格子上,只要谁能用地毯将除公主站立的地方外的所有地方盖上,美丽漂亮聪慧的公主就是他的人了。公主这一个方格不能用地毯盖住,毯子的形状有所规定,只能有四种选择(如下图所示):

这里写图片描述

并且每一方格只能用一层地毯,迷宫的大小为(2^K)^2的方形。当然,也不能让公主无限制的在那儿等,对吧?由于你使用的是计算机,所以实现时间为ls。

Input

第一行:k,即给定被填补迷宫的大小为(2^K)^2
第二行:x y,即给出公主所在方格的坐标(x为行坐标,y为列坐标),x和y之间有一个空格隔开。

Output

将迷宫填补完整的方案:每一补(行)为x y c(x,y为毯子左上角的行坐标和列坐标,c为使用毯子的形状,具体见上面的图,毯子形状分别用1、2、3、4表示,x、y、c之问用一个空格隔开)。按x,y,c的字典序输出。

Sample Input

2
3 3

Sample Output

1 1 4
1 3 2
2 2 4
3 1 1
3 3 3

Hint

分治

solution

本题的棋盘是2^k*2^k的,很容易想到分治:把棋盘切为四块,则每一块都是2^(k-1)*2^(k-1)的。有黑格的那一块可以递归解决,但其他3块并没有黑格子,应该怎么办呢?可以构造出一个黑格子,如图所示。递归边界也不难得出:k=1时一块牌就够了。
□□□□|□□□□
□■□□|□□□□
□□□□|□□□□
□□□□|◆□□□
————————-
□□□◆|◆□□□
□□□□|□□□□
□□□□|□□□□
□□□□|□□□□
原来的特殊方格用■表示,构造的特殊方格用◆表示
- 代码

#include <cstdio>
#include <cstdlib>
using namespace std;

int title = 1, size, sk = 1;
int board[2049][2049], x, y;
int t[4], br[2049][2049], ar[4][3], ok;
const int d[5][2] ={
  0,0,-1,0,1,0,0,1,0,-1
};

void chessboard(int tr, int tc, int dr, int dc, int size)//分治过程
//dc,dr表示特殊方格的坐标,tr,tr表示区域左上角的坐标,size表示当前棋盘大小
{
    if(size == 1) return;
    int t = title; //t表示填充L型骨牌的数字,title初始为1
    title++;
    int s = size / 2;  //将棋盘四等分
    if(dr <= tr + s - 1 && dc < tc + s)  //特殊格子在左上角
      chessboard(tr, tc, dr, dc, s);
    else {
    //特殊方格不在左上区域内,设置左上区域的右下角方格为特殊方格,用t填充
      board[tr + s - 1][tc + s - 1] = t;
      chessboard(tr, tc, tr + s - 1, tc + s -1, s);
    }
    if(dr < tr + s && dc >= tc + s) //特殊格子在右上区域内
      chessboard(tr, tc + s, dr, dc, s);
    else {
    //特殊方格不在右上区域内,设置右上区域的最左下角方格为特殊方格,用t填充
      board[tr + s - 1][tc + s] = t;
      chessboard(tr, tc + s,tr + s - 1, tc + s, s);
    }
    if(dr >= tr + s && dc < tc + s) //特殊格子不在在左下区域
      chessboard(tr + s, tc, dr, dc, s);
    else {
    //特殊方格不在左下区域类内,设置左下区域的最右上角为特殊方格,用t填充
      board[tr + s][tc + s - 1] = 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 {
    //特殊方格不在右下区域内,设置右下区域的最左上角为特殊方格,用t填充
      board[tr + s][tc + s] = t;
      chessboard(tr + s, tc + s, tr + s, tc + s, s);
    }
}

int judge1()
{
    ar[2][1] = ar[1][1] + 1;
    ar[2][2] = ar[1][2];
    ar[3][1] = ar[2][1];
    ar[3][2] = ar[2][2] + 1;
    if(board[ar[2][1]][ar[2][2]] == board[ar[1][1]][ar[1][2]]
     &&board[ar[3][1]][ar[3][2]] == board[ar[1][1]][ar[1][2]])
       return 1;
    return 0;
}

int judge2()
{
    ar[2][1] = ar[1][1];
    ar[2][2] = ar[1][2] + 1;
    ar[3][1] = ar[2][1] + 1;
    ar[3][2] = ar[2][2];
    if(board[ar[2][1]][ar[2][2]] == board[ar[1][1]][ar[1][2]]
     &&board[ar[3][1]][ar[3][2]] == board[ar[1][1]][ar[1][2]])
       return 1;
    return 0;
}

int judge3()
{
    ar[2][1] = ar[1][1] + 1;
    ar[2][2] = ar[1][2];
    ar[3][1] = ar[2][1];
    ar[3][2] = ar[2][2] - 1;
    if(board[ar[2][1]][ar[2][2]] == board[ar[1][1]][ar[1][2]]
     &&board[ar[3][1]][ar[3][2]] == board[ar[1][1]][ar[1][2]])
       return 1;
    return 0;
}

int judge4()
{
    ar[2][1] = ar[1][1];
    ar[2][2] = ar[1][2] + 1;
    ar[3][1] = ar[1][1] + 1;
    ar[3][2] = ar[1][2];
    if(board[ar[2][1]][ar[2][2]] == board[ar[1][1]][ar[1][2]]
     &&board[ar[3][1]][ar[3][2]] == board[ar[1][1]][ar[1][2]])
       return 1;
    return 0;
}

void dfs(int i, int a, int b) //判读格子类型
{
    if(1) {
      if(judge1()) {
        t[1] = ar[1][1];
        t[2] = ar[1][2];
        t[3] = 1;
        br[ar[2][1]][ar[2][2]] = 1; 
        br[ar[3][1]][ar[3][2]] = 1;
      }
      else if(judge2()) {
        t[1] = ar[1][1];
        t[2] = ar[1][2];
        t[3] = 2;
        br[ar[2][1]][ar[2][2]] = 1; 
        br[ar[3][1]][ar[3][2]] = 1;
      }else if(judge3()) {
        t[1] = ar[1][1];
        t[2] = ar[3][2];
        t[3] = 3;
        br[ar[2][1]][ar[2][2]] = 1; 
        br[ar[3][1]][ar[3][2]] = 1;
      }else if(judge4()){
        t[1] = ar[1][1];
        t[2] = ar[1][2];
        t[3] = 4;
        br[ar[2][1]][ar[2][2]] = 1; 
        br[ar[3][1]][ar[3][2]] = 1;
      }
       return;
    }
}

int main()
{
    int i, j;
    scanf("%d", &size);
    for(i = 1; i <= size; i++)
      sk *= 2;
    scanf("%d%d", &x, &y);
    chessboard(1, 1, x, y, sk);
    for(i = 1; i <= sk; i++)
      for(j = 1; j <= sk; j++)
        if(!br[i][j] && board[i][j]) {
            ok = 0;
            ar[1][1] = i; ar[1][2] = j;
            br[i][j] = 1;
            dfs(2, i, j);
            printf("%d %d %d\n", t[1], t[2], t[3]);
        }  
    return 0;  
}

注:本程序只能在校内测试网站通过,如果读者想通过codevs1496还需自行编写代码(主要因为地毯输出顺序的问题)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值