生长树模型

有这么一颗树,按照一定的规则进行成长:

1)      F : 表示在原来的方向的基础上水平生长,即在原来的方向的基础上画一横

2)      + : 增加45度

3)      -  : 减小45度

4)      [ :  记录该节点末的当前状态,下次变化从该节点末开始(相当于压入堆栈push操作)

5)      ] :  从上次记录的节点末恢复操作(相当于出栈操作pop)

一棵树的原始形状如下:

F[+F]F[-F]F

第一次生长以后变为:

F[+F]F[-F]F[+F[+F]F[-F]F]F[+F]F[-F]F[-F[+F]F[-F]F]F[+F]F[-F]F

第二次生长以后变为:

F[+F]F[-F]F[+F[+F]F[-F]F]F[+F]F[-F]F[-F[+F]F[-F]F]F[+F]F[-F]F[+F[+F]F[-F]F[+F[+F]F[-F]F]F[+F]F[-F]F[-F[+F]F[-F]F]F[+F]F[-F]F]F[+F]F[-F]F[+F[+F]F[-F]F]F[+F]F[-F]F[-F[+F]F[-F]F]F[+F]F[-F]F[-F[+F]F[-F]F[+F[+F]F[-F]F]F[+F]F[-F]F[-F[+F]F[-F]F]F[+F]F[-F]F]F[+F]F[-F]F[+F[+F]F[-F]F]F[+F]F[-F]F[-F[+F]F[-F]F]F[+F]F[-F]F


下图是根据上面给定的字符串生成的图形:

要求输入如下:

N                         //生长树繁殖的次数, N的范围:  1 <= N <=10

F[+F]F[-F]F   //生长树原始的样子,就其实暗含生成规则,要求原始的样子不能超过100个字符

要求输出:

生长树在原始字符串的基础上,经过N次生长后的样子,打印其字符串


这题看起来好复杂,其实稍加分析一下,问题就明朗化了,下面请看分析:

首先根据给定的字符串顺序和成长规则,画出原始图,这里我把他放大了,而且它是按照A->B->C->D->E的顺序进行成长的

经过第一次成长之后,其实是将原来形状按照生长规则,在原来的每个分支上繁殖,这里的分支指的就是A,B,C,D,E几个点:

其实A,B,C,D,E几个点的实质就是生长规则

仔细看下上面的图,其实很容易看出来,就是用原始形状替换原来的A,B,C,D,E几个分支,这样就形成了第一次生长。

同理,第二次生长,其实就是在第一次生长的基础上,用第一次生成好的图,再去替换A,B,C,D,E,这样就可以得到第二次生长以后的图。

问题分析到了这里,其实已经可以看出端倪来了。其实可以不用管成长规则:+,-,[,]

下面还是有2中方法去解体:

方法1:

第一次成长,轮询原始的字符串,找到字符'F'的地方,就用原来字符串去替换,如果不是'F',就不理会

第二次成长,以第一次成长好的字符串为基础,再次轮询,找到'F'的地方,就用原始字符串去替换,如果不是'F',就不理会

依此类推,直到N次成长结束。

下面给出详细的代码,请参考:

  1. #include <iostream>
    #include <string>
    #include <string.h>
  2. using namespace std;
  3. //把最终的结果result按引用传递进来,seed表示原始的字符串,seedLength代表原始字符串的长度
  4. void replace(string& result, const char* seed, const int seedLength)
  5. {
  6.     //把每次result的结果复制到一个临时的symbol字符串中,result会根据第i次生长后,产生不同的字符串
  7.     char* symbol = NULL;
  8.     int symbolLen = result.length();
  9.     symbol = new char[symbolLen + 1];
  10.     memset(symbol, 0x00, symbolLen+ 1 );
  11.     strcpy(symbol,result.c_str());
  12.     //在symbol中找字符"F"
  13.     symbol = strstr(symbol, "F");
  14.     //如果在symbol找到了"F",则进行插入替换
  15.     while( NULL != symbol)
  16.     {
  17.         char* tmp = NULL;
  18.         int tmpLen = strlen(result.c_str());
  19.         //这里应该多分配一个字符,应该有个+1,但是仔细考虑一下,是替换操作,"F"本身就占了一个字符,所以就不加1了
  20.         tmp = new char[tmpLen + seedLength];
  21.         //分配一个tmp临时字符指针,并且初始化
  22.         memset(tmp, 0x00, tmpLen + seedLength);
  23.         //下面的三步要合起来理解,就是找到一个"F"以后,用种子去替换这个"F"
  24.         strncpy(tmp, result.c_str(), tmpLen - strlen(symbol));    
  25.         strncat(tmp, seed, seedLength);
  26.         strncat(tmp, symbol + 1, strlen(symbol) - 1);
  27.         //把这次的替换赋值给最终的结果
  28.         result.assign(tmp);
  29.         delete[] tmp;        //不要忘记delete,防止内存泄漏
  30.         //替换完以后指针自加1,指向下一个字符
  31.         symbol = symbol + 1;
  32.         //从当前字符开始的位置再次寻找"F",找不到就返回NULL;找到就返回以"F"开头的新的字符串
  33.         symbol = strstr(symbol, "F");
  34.     }
  35.     delete[] symbol;   //不要忘记delete,防止内存泄漏
  36. }
  37. int main(int argc, char** argv)
  38. {
  39.     char input[100];
  40.     int count, i;
  41.     int seedLength;
  42.     cin >> count;
  43.     cin >> input;
  44.     string Answer;
  45.     const char* seed = input;
  46.     seedLength = strlen(seed);
  47.     //循环N次,也即成长N次
  48.     for(i=0;i<count;i++)
  49.     {
  50.         //i为0的时候设下一个种子,就是原始字符串(成长规则)
  51.         if(0 == i)
  52.         {
  53.             Answer.assign(seed);
  54.         }
  55.         else
  56.         {
  57.             replace(Answer, seed, seedLength);
  58.         }
  59.     }
  60.     cout << Answer << endl;
  61.     return 0;
  62. }


方法2:再次考虑递归调用

最后一次生成的结果,是前一次生成的结果替换上成长规则,就是例题中的A,B,C,D,E几个点;

一直递归到N等于1的时候,这时就是开始输入的成长规则。

  1. #include <iostream>
  2. #include <string>
  3. #include <cstdio>
  4. using namespace std;
  5. string Answer;
  6. string str;
  7. int len;
  8. void replace(int n)
  9. {
  10.     if(n == 1)
  11.     {
  12.         Answer += str;
  13.         return;
  14.     }
  15.     int i;
  16.     for(i = 0; i < len; i++)
  17.     {
  18.         if(str[i] == 'F')
  19.         {
  20.             replace(n-1);
  21.         }
  22.         else
  23.         {
  24.             Answer += str[i];
  25.         }
  26.     }
  27. }
  28. int main()
  29. {
  30.     int n;
  31.     cin >> n;
  32.     cin >> str;
  33.     len = str.length();
  34.     Answer = "";
  35.     replace(n);
  36.     cout << Answer << endl;
  37.     return 0;
  38. }


最后给出几组测试数据:

4

F-F++F-F

结果为:

F-F++F-F-F-F++F-F++F-F++F-F-F-F++F-F-F-F++F-F-F-F++F-F++F-F++F-F-F-F++F-F++F-F++F-F-F-F++F-F++F-F++F-F-F-F++F-F-F-F++F-F-F-F++F-F++F-F++F-F-F-F++F-F-F-F++F-F-F-F++F-F++F-F++F-F-F-F++F-F-F-F++F-F-F-F++F-F++F-F++F-F-F-F++F-F++F-F++F-F-F-F++F-F++F-F++F-F-F-F++F-F-F-F++F-F-F-F++F-F++F-F++F-F-F-F++F-F++F-F++F-F-F-F++F-F++F-F++F-F-F-F++F-F-F-F++F-F-F-F++F-F++F-F++F-F-F-F++F-F++F-F++F-F-F-F++F-F++F-F++F-F-F-F++F-F-F-F++F-F-F-F++F-F++F-F++F-F-F-F++F-F-F-F++F-F-F-F++F-F++F-F++F-F-F-F++F-F-F-F++F-F-F-F++F-F++F-F++F-F-F-F++F-F++F-F++F-F-F-F++F-F++F-F++F-F-F-F++F-F-F-F++F-F-F-F++F-F++F-F++F-F-F-F++F-F

3

F+F--F+F

结果为:

F+F--F+F+F+F--F+F--F+F--F+F+F+F--F+F+F+F--F+F+F+F--F+F--F+F--F+F+F+F--F+F--F+F--F+F+F+F--F+F--F+F--F+F+F+F--F+F+F+F--F+F+F+F--F+F--F+F--F+F+F+F--F+F

3

F[-F+[F-F]]

结果为:

F[-F+[F-F]][-F[-F+[F-F]]+[F[-F+[F-F]]-F[-F+[F-F]]]][-F[-F+[F-F]][-F[-F+[F-F]]+[F[-F+[F-F]]-F[-F+[F-F]]]]+[F[-F+[F-F]][-F[-F+[F-F]]+[F[-F+[F-F]]-F[-F+[F-F]]]]-F[-F+[F-F]][-F[-F+[F-F]]+[F[-F+[F-F]]-F[-F+[F-F]]]]]]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值