一、题目洛谷P5461赦免战俘
二、解法
分析:每次都是先处理一个大的矩阵,处理大矩阵的时候是把这个矩阵按条件分为四个,左上角不处理,右上角、左下角、右下角需要做相同的处理,相同的处理就是:把这当前的矩形再分为四部分,左上角不处理,右上角、左下角、右下角需要做相同的处理……到什么时候结束呢?一直到当前的这个矩形不能再分的时候为止,什么时候不能再分呢?即边长为0 的时候。
1、怎么确定每次需要进行分割的矩阵?
每次处理的时候都要看三个矩阵,即右上角,左上角,右下角,为了区别,用矩阵左上角的坐标+边长就可以确定要处理的矩形。每一次处理三个矩形的时候,矩形的边长都是一样的,到下次处理的时候,边长要除以2。
2、画图
假设n是2,边长为4,第一次就是一个大的正方形,要处理以图中1,2,3为顶点的小矩形,注意大矩形的边长为4,3个小矩形的边长为2。
然而三个小矩形还要继续分割下去,就是把自己看成一个大的矩形,然后再对自己的边长除以2,于是有了第二次处理,第一次的3个小矩形的1,2, 3顶点,这次变成了对于当前矩形的顶点,这次有三个需要分隔的矩形,每个矩形都要依据3个顶点再进行分割处理,每个矩形相对应位置顶点的变化是一样的,边长要渐少一半。
每个黄色的矩形是要再次进行分割的矩形,但是在计算每个黄色矩形要分割的三个矩形的时候,发现要分割的矩形的边长为0,就是无法分割了,于是把当前的每个小格子置为1.
3、遍历过程
1、递归常规解法
#include<cstdio>
#include<cmath>
#include<iostream>
using namespace std;
int a[1030][1030], n;//方形数组记录每名战俘是否被豁免
void shemian(int x, int y, int b) {//把顶点为x,y,边长为b的矩阵进行分割
if (b == 0) a[x][y] = 1;//如果这个格子不能再分,那这个格子的战俘无法赦免
else {
shemian(x + b / 2, y, b / 2);//右上矩阵
shemian(x, y + b / 2, b / 2);//左下矩阵
shemian(x + b / 2, y + b / 2, b / 2);//右下矩阵
}
}
void output(int b) {
for (int i = 0; i < b; i++) {
for (int j = 0; j < b; j++)
cout << a[i][j] <<" ";
cout << endl;
}
}
int main() {
scanf("%d", &n);
int bian = pow(2, n);//计算边长
shemian(0, 0, bian);//赦免战俘程序
output(bian);//输出
return 0;
}
2、递归解法+左移
#include<cstdio>
#include<cmath>
#include<iostream>
using namespace std;
int a[1030][1030], n;//方形数组记录每名战俘是否被豁免
void shemian(int x, int y, int b) {
if (b == 0) a[x][y] = 1;//如果这个格子不能再分,那这个格子的战俘无法赦免
else {
shemian(x + (1 << b - 1), y, b - 1);//右上矩阵
shemian(x, y + (1 << b - 1), b - 1);//左下矩阵
shemian(x + (1 << b - 1), y + (1 << b - 1), b - 1);//右下矩阵
}
}
void output(int b) {
for (int i = 0; i < 1 << b; i++) {
for (int j = 0; j < 1 << b; j++)
cout << a[i][j] <<" ";
cout << endl;
}
}
int main() {
scanf("%d", &n);
shemian(0, 0, n);//赦免战俘程序
output(n);//输出
return 0;
}