看前须知
考试回顾
网络打印机选择(北京学院数据结构18级期末压轴题)——伪树状数组(这题杀我)(ಥ_ಥ).
图的直径(士谔书院15级期末)——求有向图的最大路径:Floyd的妙用.
快逃离卷怪统治的BUAA——求树中的最短路径+中序和后序恢复二叉树.
题目内容
问题描述
zhouEnshen一觉醒来,发现自己在一个卷怪统治的BUAA中上课,他多方打听,才知道如果要回到表世界,就必须穿越一个个教学楼,最终才能从这个恐怖的BUAA逃离
zhouEnshen发现这些教学楼的结构很像二叉树,同时他也买到了一份包含着每个教学楼的BUAA地图,他身处这个树形BUAA的根部,必须走到叶子节点处才能返回表世界。但zhouEnshen没有上帝视角,很难决定自己走哪条路,请你根据zhouEnshen已有的信息判断,他选择那条路才能最快逃脱(认为经过教学楼走廊数最少者可以最快逃脱)。为了简化问题,不考虑从一个教学楼到另一个之间的教学楼。
输入形式
多组输入数据,每组包含两行。分别为二叉树的中序遍历和后序遍历,每个节点代表一个教学楼,数字是该教学楼内的走廊的数目。节点之间用一个空格隔开。
在每组遍历中,不会出现空树或者重复数字的情况。保证数字在int范围内。
输出形式
对于每组数据,输出一行,为zhouEnshen可以选择的最快路径的终点(输出该叶节点的值即可),如果有两条以上最短路,输出值较小的那个终点。
样例
【输入】
3 2 1 4 5 7 6
3 1 2 5 6 7 4
10
10
【输出】
1
10
样例说明
【样例说明】
对于第一组数据恢复二叉树后,选择的路径为4 —> 2 —> 1
对于第二组数据恢复二叉树后,选择的路径为 10
题解
思考和详解
这个题有三个难点,第一个是怎么输入数据。没错,真的这是一个让人觉得不可思议的难点,想想看,如何测试多组数据而这些数据是由不知道长度的int型数组组成。我们之前在进行多组数据测试的时候都是利用数组的长度或则数据的组数来确定EOF的,但是这里不行,我们必须要先用字符串存下来实现NULL判断数据是否停止输入,再通过字符串转int型数组实现真正的数据读入,利用sscanf来读入,我相信绝大多数人都忘了怎么用
第二个难点是如何利用二叉树的中序遍历和后序遍历恢复二叉树,其实我们模拟在纸上的操作就行,首先后序数组的最后一个是根,然后在中序遍历数组里找到根作为分界点,分左右两边为左子树的中序遍历和右子树的中序遍历,同时后序遍历数组也利用中序数组的分界点确定左子树后序遍历的节点数和右子树后序遍历的节点数,然后递归重复处理操作知道数组用完为止。
第三个难点在于怎么求最短路径,其实利用**DFS(二叉树的前序遍历)**递归处理就OK。
参考代码
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
typedef struct TreeNode {
int val;
struct TreeNode *left;
struct TreeNode *right;
int path;
}Tree,*Treep;
struct leafNode{ //树叶节点信息
int path; //路径值
int val; //该树叶节点的名
}node[200];
Treep root=NULL,t;
int top=0;
struct TreeNode* buildTree(int* inorder, int inorderSize, int* postorder, int postorderSize){ //恢复二叉树
int p=postorderSize-1,i=0; //p是后序遍历的倒数第一个数
struct TreeNode* newNode;
if(postorder == NULL || inorder == NULL) return NULL;
if(postorderSize <= 0 || inorderSize <= 0 ) return NULL;
newNode=(struct TreeNode*)malloc(sizeof(struct TreeNode));
newNode->val=postorder[p]; //利用后序遍历的倒数第一个构造根节点
newNode->left=newNode->right=NULL;
for(i=0;i<inorderSize;i++)
if(newNode->val == inorder[i]) //在中序遍历找到根节点
{
newNode->left=buildTree(inorder,i,postorder,i); //递归处理
newNode->right=buildTree(inorder+i+1,inorderSize-i-1,postorder+i,postorderSize-i-1); //递归处理
}
return newNode;
}
void CauculatePath(Treep t,int path)
{
if(t!=NULL){
t->path=path+t->val; //算路径总值
CauculatePath(t->left,t->path); //算路径总值
CauculatePath(t->right,t->path); //算路径总值
}
}
void SortLeaves(Treep t)
{
if(t!=NULL){
if(t->left==NULL && t->right==NULL)
{
node[top].path=t->path,node[top].val=t->val;// 记录叶节点信息
top++; //用数组存下来
}
SortLeaves(t->left);
SortLeaves(t->right);
}
}
int compare(const void*p1,const void*p2)
{
struct leafNode *a=(struct leafNode*)p1;
struct leafNode *b=(struct leafNode*)p2;
if(a->path!=b->path )return a->path-b->path; //根据路径总值排序
else return a->val-b->val;
}
int main()
{
int inorder[200],postorder[200],inorderSize,postorderSize,tmp,i,path=0,a,offset;
char s1[200],s2[200];
char ch;
while(gets(s1)!=NULL){ //难点
gets(s2);
memset(inorder,0,sizeof(inorder));
memset(postorder,0,sizeof(postorder));
memset(node,0,sizeof(node));
root=NULL;
offset=top=0;
int readlen;
while(sscanf(s1+offset,"%d%n",&a,&readlen)==1) //获得一个数
{
offset+=readlen;
inorder[top]=a;
top++;
}
offset=0,top=0;
while(sscanf(s2+offset,"%d%n",&a,&readlen)==1){ //获得一个数
offset+=readlen;
postorder[top]=a;
top++;
}
inorderSize=postorderSize=top; //记录遍历数组的总数
top=0;
root=buildTree(inorder, inorderSize, postorder, postorderSize);//恢复二叉树
CauculatePath(root,path); //计算路径总值
SortLeaves(root); //存树叶结点
qsort(node,top,sizeof(struct leafNode),compare); //排序
printf("%d\n",node[0].val);
}
}