《算法艺术与信息学竞赛》之 递归与分治法 例一 折纸痕

来源:互联网 发布:淘宝网非主流女装 编辑:程序博客网 时间:2024/04/30 03:24

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):
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 (1 ≤ N ≤ 13). 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 ‘ˆ’.

这道题是一个非常恶心的模拟题,在代码上用递推写感觉会好一些,不过差不多。思想其实很简单,就是将之前的图形进行旋转,但对于已知图形的旋转处理起来会非常麻烦,我们可以发现一个优美的性质,在一个图形旋转时,其衍生出的新图形的一半时旋转得来的,还有一部分可以直接平移得到,这里减少了很多代码量。我们可以先维护一个walk数组来表示每一步怎么走,再处理图形,因为图形的边界并不清楚,数组要尽量开大些,并从数组的中间开始递推,注意要维护好每一行的最大宽度,多输出的空格会判错。代码如下:
#include<bits/stdc++.h>  using namespace std;  int n;  char s[50000][2000];int main(){    while(scanf("%d",&n)&&n){        memset(s,0,sizeof(s));        int cnt=1;        char walk[50000];//存每一步的方向         walk[1]='r';        walk[2]='u';        walk[3]='\0';        while(cnt<n){//逐步递推             int len=strlen(walk+1);            for(int i=1;i<=len;i++){                if(i<=len/2){//旋转90°                     if(walk[i]=='l')walk[i+len]='r';                    else if(walk[i]=='r')walk[i+len]='l';                    else if(walk[i]=='u')walk[i+len]='d';                    else walk[i+len]='u';                }                else walk[i+len]=walk[i];//可以找到规律发现大于len/2的后面i+len与i是相同的 (因为相当于是逆时针旋转后再顺时针旋转)             }            cnt++;            walk[len*2+1]='\0';        }        int min_r=25000,max_r=25000,min_c,max_c[50000];//max_c储存着每一行的最大列数,防止多输出空格         for(int i=1;i<=25000;i++)            max_c[i]=-0x3f3f3f3f;//初值赋为负无穷        int cur_r=25000,cur_c=1000;//这里的初值赋为数组大小的一半,因为图可以向不同方向延伸,故赋为中间点最不可能越界        min_c=1000;       max_c[25000]=1000;       int len=strlen(walk+1);       s[cur_r][cur_c]='_';       for(int i=2;i<=len;i++){//开始根据不同的walk方式来拓展出图形             if(walk[i-1]=='r'){                if(walk[i]=='u'){                    cur_c++;                    s[cur_r][cur_c]='|';                }                else if(walk[i]=='d'){                    cur_r++;                    cur_c++;                    s[cur_r][cur_c]='|';                }            }            else if(walk[i-1]=='l'){                  if(walk[i]=='u'){                    cur_c--;                    s[cur_r][cur_c]='|';                }                else{                    cur_r++;                    cur_c--;                    s[cur_r][cur_c]='|';                }              }            else if(walk[i-1]=='u'){                  if(walk[i]=='r'){                    cur_r--;                    cur_c++;                    s[cur_r][cur_c]='_';}                    else{                        cur_r--;                        cur_c--;                        s[cur_r][cur_c]='_';                    }            }            else{                if(walk[i]=='r'){                    cur_c++;                    s[cur_r][cur_c]='_';                }                else{                    cur_c--;                    s[cur_r][cur_c]='_';                }            }            min_r=min(min_r,cur_r);max_r=max(max_r,cur_r);            min_c=min(min_c,cur_c);max_c[cur_r]=max(max_c[cur_r],cur_c);//更新边界值         }        for(int i=min_r;i<=max_r;i++){            for(int j=min_c;j<=max_c[i];j++){                if(s[i][j]==0)                    printf(" ");                else printf("%c",s[i][j]);            }            printf("\n");        }        printf("^\n");    }    return 0;}
本题的思想是参考了一篇很巧妙的博客的:

http://blog.csdn.net/weizhuwyzc000/article/details/47038989

对于代码改动不大,思想真的很巧妙,建议读者们阅读一下,在这里%一波大佬。
阅读全文
0 0
原创粉丝点击