Uva - 177 - Paper Folding

If a large sheet of paper is folded in half, then in half again, etc, with all the folds parallel, then opened up flat, there are a series of parallel creases, some pointing up and some down, dividing the paper into fractions of the original length. If the paper is only opened ``half-way'' up, so every crease forms a 90 degree angle, then (viewed end-on) it forms a ``dragon curve''. For example, if four successive folds are made, then the following curve is seen (note that it does not cross itself, but two corners touch):

picture23

Write a program to draw the curve which appears after N folds. The exact specification of the curve is as follows:

  • The paper starts flat, with the ``start edge'' on the left, looking at it from above.
  • The right half is folded over so it lies on top of the left half, then the right half of the new double sheet is folded on top of the left, to form a 4-thick sheet, and so on, for N folds.
  • Then every fold is opened from a 180 degree bend to a 90 degree bend.
  • Finally the bottom edge of the paper is viewed end-on to see the dragon curve.

From this view, the only unchanged part of the original paper is the piece containing the ``start edge'', and this piece will be horizontal, with the ``start edge'' on the left. This uniquely defines the curve. In the above picture, the ``start edge'' is the left end of the rightmost bottom horizontal piece (marked `s'). Horizontal pieces are to be displayed with the underscore character ``_'', and vertical pieces with the ``|'' character.

Input

Input will consist of a series of lines, each with a single number N ( tex2html_wrap_inline50 ). The end of the input will be marked by a line containing a zero.

Output

Output will consist of a series of dragon curves, one for each value of N in the input. Your picture must be shifted as far left, and as high as possible. Note that for large N, the picture will be greater than 80 characters wide, so it will look messy on the screen. The pattern for each different number of folds is terminated by a line containing a single `^'.

Sample input

2
4
1
0

Sample output

|_
 _|
^
   _   _
  |_|_| |_
   _|    _|
|_|
^
_|
^

经典题目吧,感觉是练习递归的,可是有非递归的方式做,果断直接迭代了。

观察每次展开新部分和旧部分,新的尾和旧的头相对应,依次往中间走对应起来,得到对应关系:

上变成左

下变成右

左变成下

右变成上

画图的部分用map存储。

AC代码:

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cctype>
#include <cstring>
#include <string>
#include <sstream>
#include <vector>
#include <set>
#include <map>
#include <algorithm>
#include <stack>
#include <queue>
#include <bitset> 
#include <cassert> 
#include <cmath>
#include <functional>

using namespace std;

const int maxn = 1 << 15;
int A[maxn];

// 0,1,2,3分别是上下左右
int trans[] = { 2, 3, 1, 0 };

map<int, set< pair<int, int> > > P;

void build(int n)
{
	int m = 1;
	A[0] = 3;
	for (int i = 1; i <= n; i++) {
		for (int j = m - 1, k = m; j >= 0; j--, k++) { // 算出下一次展开的位置
			A[k] = trans[A[j]];
		}
		m <<= 1;
	}
	int x = -1, y = 0, px = 0, py = 0;
	P.clear();
	// 把每个短线的位置计算出来,并放入P中
	for (int i = 0; i < m; i++) {
		if (A[i] == 0) {
			x = px << 1;
			y = py;
			P[y].insert(make_pair(x, 0));
			py++;
		}
		else if (A[i] == 1) {
			x = px << 1;
			y = py - 1;
			P[y].insert(make_pair(x, 1));
			py--;
		}
		else if (A[i] == 2) {
			x = (px << 1) - 1;
			y = py;
			P[y].insert(make_pair(x, 2));
			px--;
		}
		else {
			x = (px << 1) + 1;
			y = py;
			P[y].insert(make_pair(x, 3));
			px++;
		}
	}
}

void draw()
{
	// 设置无穷大和无穷小,具体为什么在这篇题解前一篇博文有说明
	int mxy = -0x3f3f3f3f, mnx = 0x3f3f3f3f;
	for (map<int, set< pair<int, int> > >::iterator it = P.begin();
		it != P.end(); it++) {
		mxy = max(mxy, it->first);
		for (set< pair<int, int> >::iterator jt = it->second.begin();
			jt != it->second.end(); jt++) {
			mnx = min(mnx, jt->first);
		}
	}
	// 从最上面一行画起,所以需要反向遍历
	for (map<int, set< pair<int, int> > >::reverse_iterator it = P.rbegin();
		it != P.rend(); it++) {
		int i = mnx;
		for (set<pair<int, int> >::iterator jt = it->second.begin();
			jt != it->second.end(); jt++) {
			while (i < jt->first) {
				cout << ' ';
				i++;
			}
			i++;
			if (jt->second == 0 || jt->second == 1) {
				cout << '|';
			}
			else {
				cout << '_';
			}
		}
		cout << endl;
	}
	cout << '^' << endl;
}

int main()
{
	ios::sync_with_stdio(false);
	int n;
	while (cin >> n && n) {
		build(n);
		draw();
	}

	return 0;
}




  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值