UVa 10410 樹重建
Tree Reconstruction
Problem Description
You have just finished a compiler design homework question where you had to find the parse tree of an expression. Unfortunately you left your assignment in the library, but luckily your friend picked it up for you. Instead of e-mailing you the parse tree so that you can rewrite the solution, your friend decides to play a practical joke and sends you just the DFS and BFS trace. Rather than try to redo the entire question you decide to reconstruct the tree.
思路分析
首先這不是一道普通的根據BFS和DFS建樹,因此我們需要分析這種樹的遍歷的性質。普通性質無需多說,這裏只說必要的。
對於BFS:
同層的節點BFS編號順序在DFS中也是按順序出現的。根據這個我們可以一次遍歷算出節點 的深度。
對於DFS:
一個節點的子孫肯定在他後面,在他同層相鄰節點的前面。
對於一個節點的子孫,如果他們有的深度恰好等於這個節點的深度+1,那麽這些子孫肯定是這個節點的兒子。
有了這些性質我們就可以遞歸建樹了。
代碼展現
#include<cstdlib> #include<cstdio> #include<cmath> #include<cstring> #include<ctime> #include<iostream> #include<string> #include<vector> #include<list> #include<deque> #include<stack> #include<queue> #include<map> #include<set> #include<algorithm> //#pragma GCC optimize(2) using namespace std; #define ll long long const int maxn=1010; const int INF=0x7fffffff; inline void read(int&x){ int data=0,w=1; char ch=getchar(); while(ch!=‘-‘&&!isdigit(ch)) ch=getchar(); if(ch==‘-‘) w=-1,ch=getchar(); while(isdigit(ch)) data=10*data+ch-‘0‘,ch=getchar(); x=data*w; } void write(int x){ if(x<0) putchar(‘-‘),x=-x; if(x>9) write(x/10); putchar(‘0‘+x%10); } struct vertex{ int depth; int bfsrank; int dfsrank; list<int> edge; void clear(){ depth=bfsrank=dfsrank=0; edge.clear(); } void addedge(int v){ edge.push_back(v); } }v[maxn]; int bfsans[maxn],dfsans[maxn]; #define root bfsans[1] void build(int o,int l,int r){ // clog<<"in o:"<<o<<" l:"<<l<<" r:"<<r<<endl; for(int i=l;i<=r;++i) if(v[dfsans[i]].depth==v[o].depth+1) v[o].addedge(dfsans[i]); if(v[o].edge.size()){ list<int>::iterator i=v[o].edge.begin(),ed=v[o].edge.end(); --ed; while(i!=ed){ build(*(i++),v[*(--i)].dfsrank+1,v[*(++i)].dfsrank-1); } build(*ed,v[(*ed)].dfsrank+1,r); } } int main() { // freopen(".in","r",stdin); // freopen(".out","w",stdout); int n,whodep; while(cin>>n){ for(int i=1;i<=n;++i) v[i].clear(); for(int i=1;i<=n;++i){ read(bfsans[i]); v[bfsans[i]].bfsrank=i; } for(int i=1;i<=n;++i){ read(dfsans[i]); v[dfsans[i]].dfsrank=i; } /* clog<<"dfsrank:"<<endl; for(int i=1;i<=n;i++) clog<<i<<": "<<v[i].dfsrank<<endl;*/ v[root].depth=0; whodep=1; for(int i=2;i<=n;++i){ if(v[bfsans[i]].dfsrank<v[bfsans[i-1]].dfsrank) ++whodep; v[bfsans[i]].depth=whodep; } /* clog<<"depths: "<<endl; for(int i=1;i<=n;++i) clog<<i<<": "<<v[i].depth<<endl;*/ build(root,2,n); for(int i=1;i<=n;++i){ write(i);putchar(‘:‘);putchar(‘ ‘); if(v[i].edge.size()){ list<int>::iterator j=v[i].edge.begin(); while(j!=v[i].edge.end()){ write(*j);putchar(‘ ‘); ++j; } } putchar(‘\n‘); } } // fclose(stdin); // fclose(stdout); return 0; }
認真看了的同學應該會註意到67行我的奇怪寫法。為何不寫成build(\*i,v[\*i].dfsrank+1,v[\*(++i)].dfsrank-1);
呢?
這背後就是我寫這篇博客的主要原因。上述代碼是錯的。
萬惡之源是函數參數壓棧順序(CALLBACK),他是從右到左壓棧的。這樣的話上述代碼問題就很嚴重了。我之前就是那樣寫的,想不到這種註意事項讓我碰上了。卡了我半中午啊o(╥﹏╥)o。誰讓 std::list
教訓慘重......
UVa 10410 樹重建