43行代碼AC——例題6-8 樹(Tree,UVa 548)——解題報告

勵志用盡量少的代碼做高效的表達。


題目大意

給定二叉樹的中序和後序遍歷序列,求該二叉樹中根到葉子的路徑和最小者,若存在多個解,則選擇葉子權值最小者(葉子權值不重複)。

思路分析

此題本質是中後序建樹+求路徑最小權。
(PS:書上的數組建樹用不習慣,於是自己寫了一個指針建樹。)
關鍵在於中序和後序建樹,後序遍歷序列的最後一個元素來確定根(前序的話是第一個元素確定根),中序序列來劃分左右子樹,如此遞歸建立樹
對於路徑和求解,建樹完成後對樹進行dfs

#include<bits/stdc++.h> 
using namespace std;
struct Node {
	int v;							//值
	Node *l = NULL, *r = NULL;		//左右子樹 
};
vector<int> in, post;				//中序,後序存儲
int minsum = 0x3fffff, ans = -1;	//路徑最小和、答案(葉子節點) 
Node* createTree(int i1, int j1, int i2, int j2) {
	if(i1 >= j1 || i2 >= j2) return NULL;		//空樹
	Node* root = new Node;
	root->v = post[j2-1];			//根節點爲後續遍歷最後一個數
	int j = find(in.begin()+i1, in.begin()+j1, post[j2-1]) - in.begin();//在中序遍歷中查找該值
	root->l = createTree(i1, j, i2, i2+(j-i1));		//建立左子樹
	root->r = createTree(j+1, j1, i2+(j-i1), j2-1);	//建立右子樹
	return root; 
} 
void dfs(Node* root, int sum) {		//計算到每個葉子的路徑和並記錄最小者
	if(root->l == NULL && root->r == NULL) {		//判斷是否遍歷到頭 
		sum += root->v;
		if(sum < minsum || (sum == minsum && ans > root->v)) {
			minsum = sum;
			ans = root->v; 
		} 
		return;
	}
	if(root->l != NULL) dfs(root->l, root->v+sum);	//非空,則訪問左子樹
	if(root->r != NULL) dfs(root->r, root->v+sum);	//非空,則訪問右子樹 
}
int main() {
	string s1, s2;
	int s;
	while(getline(cin, s1) && getline(cin, s2)) {
		in.clear(); post.clear();					//初始化
		stringstream input1(s1), input2(s2);
		while(input1 >> s) in.push_back(s);
		while(input2 >> s) post.push_back(s);
		Node* btree = createTree(0, in.size(), 0, post.size());	//建樹
		minsum = 0x3fffff; dfs(btree, 0);			//遍歷計算
		printf("%d\n", ans); 
	}
	return 0;
} 

收穫:

1、鞏固了DFS
2、掌握了中後序遍歷建樹。
3、掌握了求最小權路徑的方法。


擇苦而安,擇做而樂,虛擬現實終究比不過真實精彩之萬一。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章