题目链接:
http://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=489
题目意思:
一颗二叉树用中序和后序遍历给出,让你求出从根到叶子节点的总和最小的叶子节点的值。
解题思路:
根据中序遍历序列和后序遍历序列,构建二叉树,然后用dfs求总和最小的那个叶子节点的值。
后序遍历的最后一个节点一定是根节点,根节点在中序中的位置之前的节点一定在这个根的左树上,根节点在中序的位置之后的节点一定在这个根的右树上。
据此可以用递归来建这个树,注意有的节点没有左孩子或右孩子。
代码:
#include<iostream>
#include<cstdio>
#define INF (1<<20)
using namespace std;
int inorder[11000],suborder[11000];
struct Node
{
int value,left,right;
}tree[11000];
int num,Min,ans;
int build(int start1,int end1,int start2,int end2) //建立一颗二叉树
{
if(end1<start1||end2<start2) //没有左孩子或右孩子
return 0;
tree[++num].value=suborder[end2]; //将值存入树节点中
int temp=num;
if(start1==end1) //到达叶子节点
{
tree[num].left=-1;
return num;
}
int i;
for(i=start1;i<=end1;i++) //遍历中序,找到当前节点的位置
if(inorder[i]==suborder[end2])
break;
tree[temp].left=build(start1,i-1,start2,i-start1+start2-1); //建立当前节点的左树,注意不能用tree[num].left,应为num为全局变量,会改变直至最后,wa了好多次
tree[temp].right=build(i+1,end1,i-start1+start2,end2-1); //建立当前节点的右树
return temp; //注意是return 当前的节点编号,wa了好几次
}
void DFS(int cur,int sum) //dfs求和
{
sum+=tree[cur].value;
if(tree[cur].left==-1) //如果到达了叶子节点,则返回
{
if(sum<Min)
{
Min=sum;
ans=tree[cur].value;
}
return ;
}
if(tree[cur].left==0&&tree[cur].right!=0) //遇到没有孩子的情况,不能全盘不做,要考虑还有另一个孩子
{
DFS(tree[cur].right,sum);
return ;
}
if(tree[cur].right==0&&tree[cur].left!=0)
{
DFS(tree[cur].left,sum);
return ;
}
if(tree[cur].right==0&&tree[cur].left==0) //既没有做孩子又没有右孩子
return;
DFS(tree[cur].left,sum); //从左孩子dfs
DFS(tree[cur].right,sum); //从右孩子dfs
return ;
}
int main()
{
char c;
int len1=0,len2=0;
while(scanf("%d%c",&inorder[++len1],&c)!=EOF) //注意读入的方式
{
while(c!='\n')
scanf("%d%c",&inorder[++len1],&c);
do
{
scanf("%d%c",&suborder[++len2],&c);
}while(c!='\n');
num=0;
build(1,len1,1,len2); //建树
Min=INF;
DFS(1,0); //求最大的总和的叶子节点的值
printf("%d\n",ans);
len1=len2=0; //注意每次清零
}
return 0;
}