题干:
分形,具有以非整数维形式充填空间的形态特征。通常被定义为“一个粗糙或零碎的几何形状,可以分成数个部分,且每一部分都(至少近似地)是整体缩小后的形状”,即具有自相似的性质。
一个盒状分形定义如下: 度为1的盒分形为:
X
度为2的盒分形为:
X X
X
X X
依次类推,如果B(n-1)表示n-1度的盒分形,则n度的盒分形递归定义如下:
B(n - 1) B(n - 1)
B(n - 1)
B(n - 1) B(n - 1)
请画出度为n的盒分形的图形
输入格式:
输入一系列度,每行给出一个不大于7的正整数。输入的最后一行以-1表示输入结束
输出格式:
对于每个用例,输出用'X'标记的盒状分形。在每个测试用例后输出包含一个短划线“-”的一行。
输入样例:
1
2
3
4
-1
结尾无空行
输出样例:
注意:每行的空格请输出完整。
X
-
X X
X
X X
-
X X X X
X X
X X X X
X X
X
X X
X X X X
X X
X X X X
-
X X X X X X X X
X X X X
X X X X X X X X
X X X X
X X
X X X X
X X X X X X X X
X X X X
X X X X X X X X
X X X X
X X
X X X X
X X
X
X X
X X X X
X X
X X X X
X X X X X X X X
X X X X
X X X X X X X X
X X X X
X X
X X X X
X X X X X X X X
X X X X
X X X X X X X X
-
解答:
分析:
首先,这题需要先考虑怎么个输出法。计算机不像我们人那么灵活,我们人可以从左往右写,甚至写着写着可以从上往下,或者到纸上的任意一个位置,天马行空,而计算机只能老老实实的从左往右来,遇到换行才会往下,回车才会到一行的开头。回到此题,一行一行的输出肯定是有解法的,但对于我们人来说就没那么直观了。所以我们可以先建一个二维表,先将完事的内容存在这个数组中,再全部输出。
解决了如何输出都问题,我们就可以以我们人的方式来“写”这个题了。给你一直笔一张纸,你怎么写? 我的话,必然是从最小的开始,画一个一阶的‘X’,再画一个二阶的‘X’,慢慢变大。然后,我就在画的过程中发现了,一个大‘X’可以分成5个小部分,每个小部分都是上一阶的小‘X’。这就有意思了xdm,那我岂不是可以一直CtrlC+CtrlV了,最后堆成一个巨大‘X’。
套娃是吧,套娃就递归嘛。递归是吧,递归就是每一步都结果就是由上一步来的。我们来看最后成型的超级超级巨大巨大的‘X',它照样也是由 5个小一丢丢的‘X’构成的:
(图以 n = 3为例)
我们以大‘X’的左下角作为原点,这个大‘X’分成两5块,在这个坐标系下,每一小块的左下角(这个点当成是确认位置都基准点吧)的坐标都可以确认,对应的每一个小块的位置也都确认了。我们创造一个递归函数: void box(int n, int x, int y) ,在这里面,五个小老弟间隔设为m,易得m = 3^(n - 2),那这五个小老弟的位置也就定了(坐标标在图中),代入递归方程就是
box(n - 1, x, y);
box(n - 1, x, y + 2 * m);
box(n - 1, x + m, y + m);
box(n - 1, x + 2 * m, y);
box(n - 1, x + 2 * m, y + 2 * m);
至此,五个小老弟的内容也出来了。
什么?这难道就结束了?五个小老弟里的内容是啥你还没说!NONONO,你只要拿着放大镜去看其中一个小老弟,你就会发现它里面,也有五个小小老弟,跟他爹一个样,而这五个小小弟的位置怎么定,也是一样的。这样一直下去,直到最后的n=1为止,只要输出一个小小的‘X’就可以了。
代码:
#include<bits/stdc++.h>
using namespace std;
const int Max = 1000;
char a[Max][Max];
void box(int n, int x, int y)
{
if (n == 1){
a[x][y] = 'X';
}
else {
//按照图来看
int m = pow(3, (n - 2));
box(n - 1, x, y);
box(n - 1, x, y + 2 * m);
box(n - 1, x + m, y + m);
box(n - 1, x + 2 * m, y);
box(n - 1, x + 2 * m, y + 2 * m);
}
}
int main()
{
int n;
cin >> n;
int wide; //x的宽度
int i, j;
while (n != -1){
wide = pow(3, (n - 1));
//初始化
for (i = 0; i < wide; i ++){
for (j = 0; j < wide; j ++)
a[i][j] = ' ';
a[i][j] = '\0';
}
box(n, 0, 0);
//输出
for (i = 0; i < wide; i ++){
cout << a[i] << endl;
}
cout << '-' <<endl;
cin >> n;
}
system("pause");
return 0;
}
总结:
(强行升华一下吧)其实我自己也很怕递归,因为这个思路和我们平时的解法差别挺大,经常要倒着来想问题。虽然每次知道解法之后都挺恍然大悟的,但重新遇到新的题目又不知道如何下手了。(捂脸,还是多练吧)能递归的题目应该都有共同的特点,就是重复相同的步骤(废话),我想关键就是如何在不同的地方找到相同的地方吧。(好谜语人)
也是第一次写文章,难免有很多漏洞和疏忽的地方,麻烦各位大佬能不吝赐教,指出问题,万分感谢!