【洛谷 P5461】赦免战俘 题解(分治)

赦免战俘

题目背景

借助反作弊系统,一些在月赛有抄袭作弊行为的选手被抓出来了!

题目描述

现有 2 n × 2 n ( n ≤ 10 ) 2^n\times 2^n (n\le10) 2n×2n(n10) 名作弊者站成一个正方形方阵等候 kkksc03 的发落。kkksc03 决定赦免一些作弊者。他将正方形矩阵均分为 4 个更小的正方形矩阵,每个更小的矩阵的边长是原矩阵的一半。其中左上角那一个矩阵的所有作弊者都将得到赦免,剩下 3 个小矩阵中,每一个矩阵继续分为 4 个更小的矩阵,然后通过同样的方式赦免作弊者……直到矩阵无法再分下去为止。所有没有被赦免的作弊者都将被处以棕名处罚。

给出 n n n,请输出每名作弊者的命运,其中 0 代表被赦免,1 代表不被赦免。

输入格式

一个整数 n n n

输出格式

2 n × 2 n 2^n \times 2^n 2n×2n 的 01 矩阵,代表每个人是否被赦免。数字之间有一个空格。

样例 #1

样例输入 #1

3

样例输出 #1

0 0 0 0 0 0 0 1
0 0 0 0 0 0 1 1
0 0 0 0 0 1 0 1
0 0 0 0 1 1 1 1
0 0 0 1 0 0 0 1
0 0 1 1 0 0 1 1
0 1 0 1 0 1 0 1
1 1 1 1 1 1 1 1

思路

将矩阵不断分成4个象限,将第二象限的所有元素标记为0,直到无法继续分割。

AC代码

#include 
#include 
#include 
#define AUTHOR "HEX9CF"
using namespace std;

const int maxn = 1200;
int n, m;
bool a[maxn][maxn];

void f(int x1, int x2, int y1, int y2)
{
    if (x2 - x1 < 1 || y2 - y1 < 1)
    {
        return;
    }
    int midX = (x1 + x2 - 1) / 2;
    int midY = (y1 + y2 - 1) / 2;
    for (int i = x1; i <= midX; i++)
    {
        for (int j = y1; j <= midY; j++)
        {
            a[i][j] = 0;
        }
    }
    f(x1, midX, y1, midY);         // 2
    f(midX + 1, x2, y1, midY);     // 1
    f(x1, midX, midY + 1, y2);     // 3
    f(midX + 1, x2, midY + 1, y2); // 4
}

void print(int m)
{
    for (int i = 1; i <= m; i++)
    {
        for (int j = 1; j <= m; j++)
        {
            if (j != 1)
            {
                putchar(' ');
            }
            putchar('0' + (int)a[i][j]);
        }
        putchar('\n');
    }
}

int main()
{
    memset(a, 1, sizeof(a));
    cin >> n;
    m = pow(2, n);
    f(1, m, 1, m);
    print(m);
    return 0;
}

你可能感兴趣的:(数据结构与算法,算法)