習題 6-11 樹重建(Tree Reconstruction,UVa 10410)

原題鏈接:https://vjudge.net/problem/UVA-10410
分類:樹
備註:加深理解DFS和BFS, 思維

1.在BFS序中,與點a相鄰的下一個點可能有三種身份:(1)節點a的孩子 (2)節點a的兄弟 (3)節點a的兄弟的孩子

2.在DFS序中,與點a相鄰的下一個點可能有三種身份:(1)節點a的孩子(2)節點a的後兄弟(3)與節點a無之間關係

設bfs(x)爲值爲x在BFS序列中的的下標,取DFS序列中兩相鄰節點u,v;
若bfs(u)+1=bfs(v)並且v>u,則可將v視爲u的後第一兄弟(同層要按大小關係排序)

說明:根據上面1、2點可以知道只有兩種選擇,若v是u的孩子,因爲在BFS序列中相鄰,若v不是u的兄弟,則v是u的前兄弟(優先)或者u自己的孩子,又因爲v是u的孩子,u所在層只有一個節點u。因此把v視爲其後兄弟,BFS和DFS的序列是不受影響的。

若bfs(u)+1=bfs(v)並且v<u,則v爲u的孩子(題目說明了序列的子節點按從小到大排序)

若bfs(u)+1<bfs(v),顯然v不是u的兄弟,由於u和v在DFS序列中相鄰,則v必須是u的孩子;若bfs(u)>bfs(v),則v與u無直接關係;

因此可以不斷地判斷DFS中相鄰兩個節點的關係,若干無直接關係,說明這一條路徑後續不會有繼續發展,要回去找兄弟節點或者父節點,相當於把中間某些節點刪去後建立新的相鄰關係。所以利用了stack。

思路來源博文:https://www.cnblogs.com/npugen/p/9531912.html

代碼如下:

#include<cstdio>
#include<vector>
#include<stack>
#include<algorithm>
using namespace std;
const int maxn = 1000 + 5;
int n, bfs[maxn];
vector<int>child[maxn];
//bfs中相鄰的u,v :1、u是v的前兄弟 2、u是v的父親 3、v是u前兄弟的兒子
//dfs中相鄰的u,v :1、u是v的前兄弟 2、u是v的父親 3、v和u無關係
int main(void) {
	while (~scanf("%d", &n)) {
		for (int i = 1; i <= n; i++) {
			int x; scanf("%d", &x);
			bfs[x] = i;//x在bfs序列中的位置
			child[i].clear();
		}
		stack<int>tree;
		int root; scanf("%d", &root);
		tree.push(root);
		for (int i = 1; i < n; i++) {
			int v; scanf("%d", &v);
			while (1) {
				int u = tree.top();
				if (bfs[u] + 1 < bfs[v] || (bfs[u] + 1 == bfs[v] && u > v) || u == root) {
					child[u].push_back(v);
					tree.push(v);
					break;//找到父子關係後即找後續關係
				}
				else tree.pop();
			}
		}
		for (int i = 1; i <= n; i++)
			sort(child[i].begin(), child[i].end());
		for (int i = 1; i <= n; i++) {
			printf("%d:", i);
			for (int j = 0; j < child[i].size(); j++)
				printf(" %d", child[i][j]);
			printf("\n");
		}
	}
	return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章