題意,給你一顆樹的bfs序和dfs序,結點編號小的優先歷遍,問你可能的一種樹形;
輸出每個結點的子結點。
注意到以下事實:
(1)dfs序中一個結點的子樹結點一定是連續的。
(2)bfs,dfs序中的一個結點u的后續結點一定是u或u的后兄弟結點{v},或u和{v}的后代節點{s}。
(3)如果有后兄弟結點,那么bfs序中u后面緊跟着的一定是第一后兄弟結點v1,
(4)如果有后代結點,那么dfs序中u后面緊跟着的一定是第一個子結點s1。
記結點u的bfs序記為bfs(u),dfs序記為dfs(v);
dfs序中,一個結點u,結點為v滿足dfs(v) = dfs(u) + 1,如果bfs(v) = bfs(u)+1 且 v > u;那么v一定可以視作u的第一個后兄弟結點,
如果不成立,那么v是u的子節點,可以推出u是bfs中u所在層的最后一個結點,這時候u沒有后兄弟結點,所以后面的結點一定都是他的后代結點,那么v就一定可以等效作u的兄弟結點而不改變bfs,dfs序。
到此,(5)滿足bfs(v) = bfs(u)+1 且 v > u條件的v看作是u的第一個后兄弟結點,不滿足這個條件的一定不是后兄弟結點,這個可以根據定義可證。
如果v滿足(5),根據(1),u以及子樹就訪問完了,如果v不滿足條件且bfs(v)>bfs(u) + 1那么v一定是u的子結點,如果bfs(v)<bfs(u)那么說明v是其父輩結點,而且u的子樹已經訪問完了。
迭代上述過程,用棧輔助完成,邊界條件是root,大功告成~
學習點:
1.用棧處理遞歸過程。
2.bfs,dfs線性序列的性質。
原來樹形轉線性要用到這些性質
// Rey #include<bits/stdc++.h> using namespace std; const int maxn = 1000+5; vector<int> G[maxn]; int pos[maxn]; int main() { // freopen("in.txt","r",stdin); int n; int t; while(~scanf("%d",&n)&&n){ for(int i = 1; i <= n; i++) scanf("%d",&t), pos[t] = i, G[i].clear(); int root; scanf("%d",&root); stack<int> sta; sta.push(root); for(int i = 1; i < n; i++){ scanf("%d",&t); for(;;) { int u = sta.top();if( pos[u]+1 < pos[t] || (pos[u]+1 == pos[t] && u > t) || u == root ) { G[u].push_back(t); sta.push(t); break; }else { sta.pop(); } } } for(int i = 1; i <= n; i++) { printf("%d:",i); for(int j = 0, sz = G[i].size(); j < sz; j++) printf(" %d",G[i][j]); puts(""); } } return 0; }