注意到起始长度是 ,之后每次 增加 ,两边各增大 ,所以总长度为 ,因此数组每个维度范围不应该小于 ,且一开始可以直接先铺满这个区域全部是 .
,之后每次画用 $
替代 .
即可。
使用递归来做的话, 可以设当前区域左上角下标为 ,横坐标从上往下,从坐标从左往右。观察可知,除了最中心的小十字之外,其他每一层的大十字都很有规律 (其实中间的十字也可以用相同的规律生成)。假设先不考虑中心小十字:
时,当前区域跨度是 ,可以以 为左上角,画长为 的四条直线和四个内折的角(转化为八条直线)。设
则这么一个大十字可具体为:
如图所示:
可以设一个绘制直线的函数,然后每次画第 个大十字复用 次,以减轻工作量。
那么,设 是绘制第 个大十字,有: 特别地,根据上面的十二条直线,我们发现若 ,恰能对应最中心的小十字。由此,可得 定义域为 。
绘制直线函数可以抽象为画矩形函数(长或宽为 ) ,从而避免横竖的分类讨论。
绘制直线和递归函数的具体实现参见代码:
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
char a[131][131];
void line(ll ax, ll ay, ll bx, ll by)
{
for (ll i = ax; i <= bx; ++i)
{
for (ll j = ay; j <= by; ++j)
{
a[i][j] = '$';
}
}
}
void draw(ll x, ll y, ll l, ll n)
{
if (n < 0)
{
return;
}
line(x + 2, y, x + 2 + l, y);
line(x, y + 2, x, y + 2 + l);
line(x + 2, y + 4 + l, x + 2 + l, y + 4 + l);
line(x + 4 + l, y + 2, x + 4 + l, y + 2 + l);
line(x + 2, y, x + 2, y + 2);
line(x, y + 2, x + 2, y + 2);
line(x, y + 2 + l, x + 2, y + 2 + l);
line(x + 2, y + 2 + l, x + 2, y + 4 + l);
line(x + 2 + l, y, x + 2 + l, y + 2);
line(x + 2 + l, y + 2, x + 4 + l, y + 2);
line(x + 2 + l, y + 2 + l, x + 4 + l, y + 2 + l);
line(x + 2 + l, y + 2 + l, x + 2 + l, y + 4 + l);
draw(x + 2, y + 2, l - 4, n - 1);
}
ll n, l;
signed main()
{
cin >> n;
l = 5 + 4 * n;
for (ll i = 0; i < l; ++i)
{
for (ll j = 0; j < l; ++j)
{
a[i][j] = '.';
}
}
draw(0, 0, 4 * n, n);
for (ll i = 0; i < l; ++i)
{
puts(a[i]);
}
return 0;
}