HW12-递归

上次的Hw11我忽略了ddl,结果少交了一道题,哭orz

人果然不能颓,一旦一颓就容易一颓到底。

A:Boolean Expressions

描述

The objective of the program you are going to produce is to evaluate boolean expressions as the one shown next:

Expression: ( V | V ) & F & ( F | V )


where V is for True, and F is for False. The expressions may include the following operators: ! for not , & for and, | for or , the use of parenthesis for operations grouping is also allowed.

To perform the evaluation of an expression, it will be considered the priority of the operators, the not having the highest, and the or the lowest. The program must yield V or F , as the result for each expression in the input file.
输入

The expressions are of a variable length, although will never exceed 100 symbols. Symbols may be separated by any number of spaces or no spaces at all, therefore, the total length of an expression, as a number of characters, is unknown.

The number of expressions in the input file is variable and will never be greater than 20. Each expression is presented in a new line, as shown below.
输出

For each test expression, print "Expression " followed by its sequence number, ": ", and the resulting value of the corresponding test expression. Separate the output for consecutive test expressions with a new line.

Use the same format as that shown in the sample output shown below.
样例输入

( V | V ) & F & ( F| V)
!V | V & V & !F & (F | V ) & (!F | F | !V & V)
(F&F|V|!V&!F&!(F|F&V))

样例输出

Expression 1: F
Expression 2: V
Expression 3: V

来源México and Central America 2004

 1 #include<iostream>
 2 #include<cstring>
 3 #include<cstdlib>
 4 using namespace std;
 5 bool factor_value();
 6 bool term_value();
 7 bool expression_value();
 8 int main(){
 9     int temp = 0;
10     while(cin.peek()!=EOF){
11         if(cin.peek()=='\n'){
12             cin.get();
13             continue;
14         }
15         cout<<"Expression "<<++temp<<": ";
16         bool ans = expression_value();
17         if(ans) cout<<"V"<<endl;
18         else cout<<"F"<<endl;
19     }
20     return 0;
21 }
22 bool expression_value(){
23     bool result = term_value();
24     while(1){
25         while(cin.peek()==' ') cin.get();
26         if(cin.peek()=='|'){//最低优先级
27             cin.get();
28             result |= term_value(); 
29         }
30         else break;
31     }
32     return result;
33 }
34 bool term_value(){
35     bool result = factor_value();
36     while(1){
37         while(cin.peek()==' ') cin.get();
38         if(cin.peek()=='&'){
39             cin.get();
40             result &= factor_value();
41         }
42         else break;
43     }
44     return result;
45 }
46 bool factor_value(){//!(……)类型的因子 
47     bool result = 0;
48     bool reverse = false; //有没有取反 
49     while(cin.peek()==' ') cin.get();
50     while(cin.peek()=='!'){//叹号和叹号之间没有空格应该… 
51         reverse = !reverse;
52         cin.get();
53     }
54     while(cin.peek()==' ') cin.get(); //这步操作完就不会有空格了吧 
55     if(cin.peek()=='('){
56         cin.get();
57         result = expression_value();
58         cin.get();//后括号 
59     } 
60     else{
61         if(cin.peek()=='V') result = true;
62         else result = false;
63         cin.get();
64     }
65     if(reverse) result=!result;
66     return result;
67 }

备注:嗷……这就是上课老师讲的四则表达式那道题嘛。上课没认真想,就觉得还挺有意思,现在想想其实用递归就是相当于实现了不同层次的栈,层次是由运算优先级决定的。expression_value就是最外层的,所以是优先级最差的 | ,其次是term_value也就是 & ,最后是factor_value,就是单个字母或者(……)或者!(……)这样的项。还有就是要注意时刻取空格。自己写还是挺难的……

B:文件结构“图”

描述

在计算机上看到文件系统的结构通常很有用。Microsoft Windows上面的"explorer"程序就是这样的一个例子。但是在有图形界面之前,没有图形化的表示方法的,那时候最好的方式是把目录和文件的结构显示成一个"图"的样子,而且使用缩排的形式来表示目录的结构。比如:

ROOT
| dir1
| file1
| file2
| file3
| dir2
| dir3
| file1
file1
file2

这个图说明:ROOT目录包括三个子目录和两个文件。第一个子目录包含3个文件,第二个子目录是空的,第三个子目录包含一个文件。

输入

你的任务是写一个程序读取一些测试数据。每组测试数据表示一个计算机的文件结构。每组测试数据以'*'结尾,而所有合理的输入数据以'#'结尾。一组测试数据包括一些文件和目录的名字(虽然在输入中我们没有给出,但是我们总假设ROOT目录是最外层的目录)。在输入中,以']'表示一个目录的内容的结束。目录名字的第一个字母是'd',文件名字的第一个字母是'f'。文件名可能有扩展名也可能没有(比如fmyfile.dat和fmyfile)。文件和目录的名字中都不包括空格,长度都不超过30。一个目录下的子目录个数和文件个数之和不超过30。

输出

在显示一个目录中内容的时候,先显示其中的子目录(如果有的话),然后再显示文件(如果有的话)。文件要求按照名字的字母表的顺序显示(目录不用按照名字的字母表顺序显示,只需要按照目录出现的先后显示)。对每一组测试数据,我们要先输出"DATA SET x:",这里x是测试数据的编号(从1开始)。在两组测试数据之间要输出一个空行来隔开。

你需要注意的是,我们使用一个'|'和5个空格来表示出缩排的层次。

样例输入

file1
file2
dir3
dir2
file1
file2
]
]
file4
dir1
]
file3
*
file2
file1
*
#

样例输出

DATA SET 1:
ROOT
|     dir3
|     |     dir2
|     |     file1
|     |     file2
|     dir1
file1
file2
file3
file4

DATA SET 2:
ROOT
file1
file2

提示

一个目录和它的子目录处于不同的层次
一个目录和它的里面的文件处于同一层次来源翻译自 Pacific Northwest 1998 的试题

 1 #include<iostream>
 2 #include<cstring>
 3 #include<cstdlib>
 4 #include<queue> //要改变思维定式……栈不一定是真的栈呢 
 5 #include<cstdio>
 6 using namespace std;
 7 int main(){
 8     int temp = 0;
 9     string s;
10     int ndir = 0; //用来计算栈里压着多少个文件夹(决定了输出几个|) 
11     bool flag=true; //避免了两重循环,来判断一组数据有没有结束 
12     priority_queue<string, vector<string>, greater<string> >pq[1001];//每个文件夹里的文件要排序,所以还是这样好一点 
13     while(1){ 
14         cin>>s;
15         if(s[0]=='#') break;
16         if(flag){
17             printf("DATA SET %d:\nROOT\n",++temp); 
18             flag = false;
19         }
20         if(s[0]=='f') pq[ndir].push(s);
21         else if(s[0]=='d'){
22             ndir++;
23             for(int i = 0; i < ndir; i++)
24                 cout<<"|     ";
25             cout<<s<<endl;
26         }
27         else if(s[0]==']'||s[0]=='*'){//一个效果
28             while(!pq[ndir].empty()){
29                 for(int i = 0; i < ndir; i++)
30                     cout<<("|     ");
31                 cout<<pq[ndir].top()<<endl;
32                 pq[ndir].pop();
33             } 
34             ndir--;    
35         }
36         if(s[0]=='*'){
37             ndir = 0;
38             flag = true;
39             cout<<endl;
40         }
41     }
42     return 0;
43 }

备注:我是不是已经丧失独立写代码的能力了……放弃递归直接用栈写,每次一想到用栈我就迫不及待地写一个#include<stack>,但其实也不一定会用到stack,比如这道题 就用一个ndir加加减减来模拟一个栈,我觉得挺巧妙的,因为ndir是一定要有的,要不然不知道是第几层文件夹,从而不知道前面要打几个“|     ”。完了用优先队列来实现每个文件夹内文件的排序,所以要开好多个优先队列,每个文件夹都有。还有就是怎么处理一组数据输入完。什么时候输出DATA SET那一行,方法是用一个flag来标记,这样就可以知道什么时候输出信息头了,我怎么连这么简单的东西都想不到了……

C:The Sierpinski Fractal

描述

Consider a regular triangular area, divide it into four equal triangles of half height and remove the one in the middle. Apply the same operation recursively to each of the three remaining triangles. If we repeated this procedure infinite times, we'd obtain something with an area of zero. The fractal that evolves this way is called the Sierpinski Triangle. Although its topological dimension is 2, its Hausdorff-Besicovitch dimension is log(3)/log(2)~1.58, a fractional value (that's why it is called a fractal). By the way, the Hausdorff-Besicovitch dimension of the Norwegian coast is approximately 1.52, its topological dimension being 1.

For this problem, you are to outline the Sierpinski Triangle up to a certain recursion depth, using just ASCII characters. Since the drawing resolution is thus fixed, you'll need to grow the picture appropriately. Draw the smallest triangle (that is not divided any further) with two slashes, to backslashes and two underscores like this:

 /\
/__\

To see how to draw larger triangles, take a look at the sample output.

输入

The input contains several testcases. Each is specified by an integer n. Input is terminated by n=0. Otherwise 1<=n<=10 indicates the recursion depth.

输出

For each test case draw an outline of the Sierpinski Triangle with a side's total length of 2n characters. Align your output to the left, that is, print the bottom leftmost slash into the first column. The output must not contain any trailing blanks. Print an empty line after each test case.

样例输入

3
2
1
0

样例输出

       /\
      /__\
     /\  /\
    /__\/__\
   /\      /\
  /__\    /__\
 /\  /\  /\  /\
/__\/__\/__\/__\

   /\
  /__\
 /\  /\
/__\/__\

 /\
/__\

提示


The Sierpinski-Triangle up to recursion depth 7

来源Ulm Local 2002

 1 #include<iostream>
 2 #include<cstring>
 3 #include<cstdlib>
 4 #include<cstdio>
 5 using namespace std;
 6 char tr[1<<11][1<<11]; 
 7 void draw(int x, int y, int depth){
 8     if(depth==1){
 9         tr[x][y+1] = '/';
10         tr[x][y+2] = '\\';
11         tr[x+1][y] = '/';
12         tr[x+1][y+3] = '\\';
13         tr[x+1][y+1] = tr[x+1][y+2] = '_'; 
14         return;
15     }
16     draw(x,y+(1<<depth-1),depth-1);//左移运算符优先级很低 
17     draw(x+(1<<depth-1),y,depth-1); 
18     draw(x+(1<<depth-1),y+(1<<depth),depth-1);
19 } 
20 int main(){
21     while(1){
22         int n;
23         cin>>n; //第几层边长就是2的几次方 
24         memset(tr,' ',sizeof(tr));//对于char数组,memset随便用 
25         if(!n) break;
26         draw(0,0,n);//以(x,y)为左端点画深度为n的三角形 
27         for(int i = 0; i < (1<<n); i++){
28             for(int j = 0; j < (2<<n); j++) //宽是高的两倍 
29                 cout<<tr[i][j];
30             cout<<endl;
31         }
32         cout<<endl;
33     }
34     return 0;
35 }

备注:

这道题翻译一下就是画三角形分型,一眼看过去又是我不会的题。子问题不能是简单的画深度为n的三角形,而是在(x,y)位置画深度为n的三角形,(x,y)是三角形的左上角(可以想象每一个三角形用一个长方形框住),为什么是一个长方形呢!因为三角形表面上是等边的,但实际上深度为1的三角形需要两行四列来存,这么简单的道理我居然想了很久……(/和\也是要占一个字符的呀),所以每个三角形的宽是高的两倍。

然后就是递归分别画三个地方的内部的三角形。好好看看图就不难理解公式,上面的三角形的坐标是(x,y+(1<<depth-1)),因为相当于是向右偏了底边的1/4,底边的边长是2^depth再*2,所以除以4的话depth只要左移一位就可以了。同理左下角的坐标是高度的1/2,右下角也很简单了。

还学到了其他知识,比如左右移运算符的优先顺序低于加减乘除,所以不用加括号;还有就是memset是以字节为单位来操作内存,所以虽然对于整型数组只能置成0或-1,但对于char数组就随便了,nice!最后就是数组要开足够大,因为刚才说的原因,开1<<10是不够大的,宽度得开1<<11。

posted @ 2020-04-19 18:48  timeaftertime  阅读(272)  评论(0编辑  收藏  举报