这个问题是一个经典的**递归分形(Fractal)**构造问题。我们需要根据给定的递归规则,在一个二维网格中填充字符 ‘X’。
1. 核心规律分析
首先,我们要确定每一级分形的大小(边长):
时,边长为 ( )。 时,由 5 个 的图形组成,排列成 的布局,边长为 ( )。 时,由 5 个 的图形组成,排列成 的布局,边长为 ( )。
通用结论: 度数为
2. 递归结构拆解
根据题干,度数为
- 左上角
- 右上角
- 中间
- 左下角
- 右下角
3. 解题思路与算法
由于 char canvas[730][730]),先初始化为空格,然后通过递归填充 ‘X’。
递归函数设计
我们可以定义一个函数 draw(int n, int r, int c),表示在起始坐标
-
递归边界:
如果
,直接在 canvas[r][c] 处填入 ‘X’。 -
递归步骤:
- 计算子图形(即
级)的边长: 。 - 根据
布局,递归调用 5 次: - 左上:
draw(n-1, r, c) - 右上:
draw(n-1, r, c + 2 * size) - 中间:
draw(n-1, r + size, c + size) - 左下:
draw(n-1, r + 2 * size, c) - 右下:
draw(n-1, r + 2 * size, c + 2 * size)
- 左上:
- 计算子图形(即
4. 关键实现细节
- 预计算幂次方: 可以先计算好
到 的值。 - 清空画布: 每次处理新的
时,或者在程序开始前,将数组初始化为空格。 - 打印处理: 打印完每一行后,注意行末的空格。题目要求输出分形结构,通常需要打印到该行最后一个 ‘X’ 或者是完整的边长宽度。根据样例,直接打印整行(包括必要的空格)即可。
- 输出分隔符: 每一个测试用例结束后,打印一个只包含短横线
-的行。
5. 伪代码示例
cpp
void draw(int n, int r, int c) {
if (n == 1) {
canvas[r][c] = 'X';
return;
}
int size = pow(3, n - 2); // 计算下一级的边长
draw(n - 1, r, c); // 左上
draw(n - 1, r, c + 2 * size); // 右上
draw(n - 1, r + size, c + size); // 中间
draw(n - 1, r + 2 * size, c); // 左下
draw(n - 1, r + 2 * size, c + 2 * size); // 右下
}
代码
cpp
#include <iostream>
#include <vector>
#include <cmath>
#include <cstring>
using namespace std;
// 全局字符数组,最大边长为 3^6 = 729
char canvas[731][731];
// 预计算 3 的幂次方,提高效率
int pow3[8];
/**
* 递归绘制盒分形
* @param n 当前分形的度数
* @param r 起始行坐标
* @param c 起始列坐标
*/
void draw(int n, int r, int c) {
if (n == 1) {
canvas[r][c] = 'X';
return;
}
// 计算子分形(n-1度)的边长
int subSize = pow3[n - 2];
// 递归填充五个位置
draw(n - 1, r, c); // 左上
draw(n - 1, r, c + 2 * subSize); // 右上
draw(n - 1, r + subSize, c + subSize); // 中间
draw(n - 1, r + 2 * subSize, c); // 左下
draw(n - 1, r + 2 * subSize, c + 2 * subSize); // 右下
}
int main() {
// 预处理 3 的幂
pow3[0] = 1;
for (int i = 1; i <= 7; ++i) pow3[i] = pow3[i - 1] * 3;
int n;
while (cin >> n && n != -1) {
int size = pow3[n - 1];
// 初始化画布为空格
for (int i = 0; i < size; ++i) {
for (int j = 0; j < size; ++j) {
canvas[i][j] = ' ';
}
canvas[i][size] = '\0'; // 方便按行打印
}
// 开始递归绘制
draw(n, 0, 0);
// 输出结果
for (int i = 0; i < size; ++i) {
// 题目要求:去掉行末多余空格可能会导致不通过,
// 建议直接输出整行。
// 此时由于末尾有 \0,可以直接按字符串输出或遍历
for (int j = 0; j < size; ++j) {
cout << canvas[i][j];
}
cout << endl;
}
cout << "-" << endl;
}
return 0;
}