题目链接:
http://acm.hust.edu.cn/vjudge/problem/viewProblem.action?id=19105
题意:
给定一棵树的后序排列和中序排列,求这棵树最小路径的叶节点的值
思路:
主要通过此题掌握什么是后序排列和中序排列,并且怎么用他们还原一棵树。
后序排列即先排左子树,再排右子树,最后排根节点。这样就决定了最后一个点为根节点。
中序排列即先排左子树,再排根节点,最后排右子树。这样就决定了根节点的左边和右边分别为左子数和右子树。
通过后序确定根节点,在中序中找到它划分为左右子树,递归实现重构树。
出错点主要是重构树的递归过程中左右子树的下标问题,WA一两次就出来啦。
当然打印出来的PDF和原题的数据范围不同导致要使用long long也是一个出错点。
源码:
#include <cstdio>
#include <cmath>
#include <cstring>
#include <string>
#include <algorithm>
#include <iostream>
using namespace std;
#define gmin(a,b) a<b?a:b
typedef long long ll;
const int MAXN = 10000+5;
char data[5*MAXN + 5];
int lv[MAXN],ji[MAXN];
int lson[MAXN],rson[MAXN];///depend on lv's standard
int ans;
ll res;
void solve(int mark,int st,int en,ll val)
{
if(st == en){
// printf("val = %d,ans = %d,st = %d,lv = %d\n",val+lv[st],ans,st,lv[st]);
if(res > val+lv[st]){
res = val + lv[st];
ans = lv[st];
}
return;
}
for(int i=st; i<=en ;i++){
if(lv[i] == ji[mark]){
if(i != en){
rson[i] = ji[mark-1];
solve(mark-1,i+1,en,val+lv[i]);
}
if(i != st){
lson[i] = ji[mark-(en-i)-1];
solve(mark-(en-i)-1,st,i-1,val+lv[i]);
}
}
}
}
int main()
{
while(gets(data) != NULL){
int len = strlen(data);
int cnt = 0;
int temp = 0;
for(int i=0; i<len; i++){
if(data[i] == ' '){
lv[cnt++] = temp;
temp = 0;
}
else if(data[i] >= '0' && data[i] <='9')
temp = temp*10 + data[i] - '0';
}
lv[cnt++] = temp;
temp = 0;
gets(data);
cnt = 0;
len = strlen(data);
for(int i=0; i<len; i++){
if(data[i] == ' '){
ji[cnt++] = temp;
temp = 0;
}
else if(data[i] >= '0' || data[i] <= '9') temp = temp*10 + data[i] - '0';
}
ji[cnt++] = temp;
memset(lson, -1, sizeof(lson));
memset(rson, -1, sizeof(rson));
res = MAXN*MAXN;
solve(cnt-1,0,cnt-1,0);
// for(int i=0; i<cnt; i++){
// if(lson[i] == -1 && rson[i] == -1){
// printf("leaf is %d\n",lv[i]);
// ans = gmin(ans, lv[i]);
// }
// }
// for(int i=0; i<cnt; i++)
// printf("for %d,lson is %d,rson is %d\n",lv[i],lson[i],rson[i]);
printf("%d\n",ans);
}
return 0;
}