上一周的程序作业一共三道题,很快就完成了,然而上课才发现有许多好的方法都没有想到,看来自己还需要很长时间来提升自己啊。
这一次对上一周的作业进行一次总结。
第一题是UVA的712 S-Tree题目,这个我在上课便写了出来,思想很朴实。但是上课又听到了一些新的方法。
第一种方法:根据输入画出树来
按照输入顺序逐渐分析。
第一个输入一个数字n(样例是3),可以得出构建一个数组,设为ID,大小是
20+21+...+2n
第二个输入是关于
xi
的输出顺序(样例给的顺序是
x3,x1,x2
)办法是利用字符数组对每一次输入进行存储,得出每个数的起始和终止位置,用两个数组存储。讲的有点绕,下面是对样例的操作。
第一次:起始位置0,终止位置0 因此start[3]=0 end[3]=0
第二次:起始位置1,终止位置2 因此start[1]=1 end[1]=2
第m次:起始位置
2m−1−1
,终止位置
2m−2
第三个输入是最下一层的值,可知起始位置
2n−1−1
,终止位置
2n−2
第四个输入比较水,不提。
第五个输入是
x1,x2,x3...
的值。根据前面得到的start和end数组,就可以把值放在树中。
以上便把输入搞定,输出便是很简单了,直接从根节点开始,如果0,往左,如果1,往右。
AC代码
#include <iostream>
#include <cstdio>
#include <cstring>
#include <string>
const int maxn = 7;
int id[1<<maxn];
char terminal[1<<maxn];
int start[maxn+5];
int end[maxn+5];
int main()//main有括号。。。
{
int C = 1;
int n;
while(scanf("%d",&n)!=EOF&&n)
{
memset(id,0,sizeof(id));
for(int i=1;i<=n;i++)
{
char variable[2];
scanf("%s",variable);
start[variable[1]-'0'] = (1<<(i-1))-1;
end[variable[1]-'0'] = (1<<i)-2;
}
scanf("%s",terminal);
int temp = (1<<n)-1;
for(int i=0;i<(1<<n);i++)
{
id[temp]=terminal[i]-'0';
temp++;
}
int m;
scanf("%d",&m);
printf("S-Tree #%d:\n",C);
C++;
int result[100];
int temp_i=0;
int temp_m = m;
while(temp_m--)
{
char value[7];
scanf("%s",value);
int len = strlen(value);
for(int i=1;i<=len;i++)
{
for(int j=start[i];j<=end[i];j++)
{
id[j] = value[i-1]-'0';
}
}
int temp = 0;
while(temp<((1<<n)-1))//
{
if(id[temp]==0)
{
temp = temp*2+1;
}else
{
temp = temp*2+2;
}
}
result[temp_i] = id[temp];
temp_i++;
}
for(int i=0;i<m;i++)
{
printf("%d",result[i]);
}
printf("\n\n");
}
}
一个好的方法
把样例给的x的顺序调过来。比如样例中给的011,但他是
x3x1x2
的顺序,所以应该是101。
调完之后,开始对给出的最后一行数组操作。开始start为0,end为
2n
。如果是1,则start变成中间的数。如果是0,则end变成中间的数。直到end和start相同,输出它们所在位置的值。
非常好的方法
利用2进制。比如给的101,输入顺序是
x3x1x2
,调整之后为110,转换成二进制,为
20∗0+21∗1+22∗1=6
,所以输出最后一行的数中第6个数。
其实想一想,也是很好想的。
对于下方图片,第一个是
x3
,如果是1,那么结果就在右半段,如果是0,结果在左半段。所以是
2n−1∗x3
,如此反复,最后便是上述所说的结果。
总结
1.二叉树的根节点从1开始,虽然浪费了0,但是方便程度大大提高
2.遇到0和1的题目,多想想二进制能不能搞吧
3.(1<< n-1)表示的是
2n−1
不是
2n−1
…