链接:
https://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=113
题意:
给你一张很大的纸,对折以后再对折,再对折……每次对折都是从右往左折,因此在折了很多次以后,
原先的大纸会变成一个窄窄的纸条。现在把这个纸条沿着折纸的痕迹打开,每次都只打开“一半”,
即把每个痕迹做成一个直角,那么从纸的一端沿着和纸面平行的方向看过去,会看到一条美妙的曲线。
给出对折的次数,请编程绘出打开后生成的曲线。
分析:
如图所示,圆圈A,B表示展开时的旋转点,其余字母代表线段。
看图找规律。线段位置变化顺序是:左上 -> 右上 -> 右下 -> 左下 -> 左上
当以B为旋转点(第三次展开)时。B左边的第一条线段是一条横线(即e),
而且所有旋转点左边的第一条线段都是横线。
因为B的左边部分是由B的下边部分旋转得来,所以其余线段可根据上面的线段位置变化顺序得出:
因为c在d的右下方,所以e的下一条线段(即f)在e的左下方。
因为b在c的右下方,所以f的下一条线段(即g)在f的左下方。
因为a在b的左下方,所以g的下一条线段(即h)在g的左上方。
依照此规律就可以生成一条完整的曲线了。
代码:
1 #include <cstdio> 2 #include <cstring> 3 4 const int dr[8] = {1, 0, 1, 0, 0, -1, 0, -1}; 5 const int dc[8] = {1, 1, -1, -1, -1, -1, 1, 1}; 6 const char dch[8+5] = "||||____"; 7 8 struct COORDINATE { 9 int r, c; //行坐标,列坐标 10 } a[9999]; //生成的线段序列,可以看作一个栈 11 12 char s[300][300]; //用一个二维数组保存图像 13 int p, sr, tr, sc, tc[300]; //栈顶指针,图像的开始行,结束行,开始列,每一行的结束列 14 15 void init(){ 16 memset(s, ' ', sizeof(s)); 17 memset(tc, 0, sizeof(tc)); 18 a[0] = (COORDINATE){150, 150}; 19 a[1] = (COORDINATE){150, 151}; 20 s[a[0].r][a[0].c] = '_'; 21 s[a[1].r][a[1].c] = '|'; 22 p = 2; sr = a[0].r; tr = a[1].r; sc = a[0].c; tc[tr] = a[1].c; 23 } 24 25 void make(int r, int c, char ch){ 26 a[p] = (COORDINATE){r, c}; 27 s[a[p].r][a[p].c] = ch; 28 if(sr > r) sr = r; 29 if(tr < r) tr = r; 30 if(sc > c) sc = c; 31 if(tc[r] < c) tc[r] = c; 32 p++; 33 } 34 35 void dfs(int d, int dep){ 36 if(d > dep) return; 37 make(a[p-1].r - 1, a[p-1].c - 1, '_'); 38 for(int i = p - 2; i > 0; i--){ 39 COORDINATE R = a[i], L = a[i-1]; 40 int d = (s[R.r][R.c] == '_') * 4 + (R.r == L.r) * 2 + (R.c > L.c); //判断下一条线段的位置 41 make(a[p-1].r + dr[d], a[p-1].c + dc[d], dch[d]); 42 } 43 dfs(d + 1, dep); //下一次展开 44 } 45 46 int main(){ 47 int n; 48 while(scanf("%d", &n) && n){ 49 init(); 50 dfs(2, n); 51 for(int r = sr; r <= tr; r++){ 52 for(int c = sc; c <= tc[r]; c++) printf("%c", s[r][c]); 53 printf("\n"); 54 } 55 printf("^\n"); 56 } 57 return 0; 58 }