本题给出一个有树性质的无向图,可以选择任何一个点做树根,要求在所有可能性中,找出树高最小的MHTs,并输出树根。
本题给出的图本身就是一棵树,不是一个最小生成树的问题。理论上求出每个节点对应的树高,然后排序即可,这样的复杂度在O(v*v),没有试过这样能不能过。
另一方面,也可以将问题转化来看,首先,先不考虑两个节点以下的情况,很显然图中入度为0的点形成的树一定不是MHTs;入度为1的点也不是,因为假设它是,则它的子节点一定会连有其它节点,否则这棵树不能包含所有节点,那么以它子节点为根的树的高度就一定会小1,即有高度更低的树,就与假设相悖。从这个角度来思考,可以尝试使用贪心的策略,形成一种类似拓扑排序的方法,逐步在图中删除入度为0或1的点,并更新相关节点的入度,直到不能再删除为止,那么最后删除的几个点的就是所要求的点。代码如下:
#include <iostream>
#include <vector>
#include <unordered_set>
#include <forward_list>
using namespace std;
class Solution {
public:
vector<int> findMinHeightTrees(int n, vector<pair<int, int> >& edges) {
if (n == 1)
return vector<int>(1, 0);
int i;
vector<unordered_set<int> > G(n);
vector<int> inDegree(n, 0);
forward_list<int> curr_nodes;
forward_list<int> next_nodes;
forward_list<int> erase_nodes;
vector<int> treesRoot;
for (i = 0; i < int(edges.size()); ++i) {
G[edges[i].second].insert(edges[i].first);
G[edges[i].first].insert(edges[i].second);
}
for (i = 0; i < n; ++i)
inDegree[i] = int(G[i].size());
for (i = 0; i < n; ++i)
curr_nodes.push_front(i);
while (n--) {
next_nodes.clear();
erase_nodes.clear();
for (forward_list<int>::iterator it = curr_nodes.begin(); it != curr_nodes.end();
++it) {
if (inDegree[*it] == 0 || inDegree[*it] == 1)
erase_nodes.push_front(*it);
else
next_nodes.push_front(*it);
}
for (forward_list<int>::iterator it = erase_nodes.begin(); it != erase_nodes.end();
++it) {
inDegree[*it] = -1;
for (unordered_set<int>::iterator giit = G[*it].begin(); giit != G[*it].end();
++giit) {
inDegree[*giit]--;
}
// G.erase(G.begin() + *it);
}
if (next_nodes.empty()) {
for (forward_list<int>::iterator it = curr_nodes.begin(); it != curr_nodes.end();
++it)
treesRoot.push_back(*it);
return treesRoot;
}
curr_nodes = next_nodes;
}
return vector<int>();
}
};
int main() {
Solution s;
int n;
vector<pair<int, int> > edges;
n = 6;
edges.push_back(make_pair(0, 3));
edges.push_back(make_pair(1, 3));
edges.push_back(make_pair(2, 3));
edges.push_back(make_pair(4, 3));
edges.push_back(make_pair(5, 4));
vector<int> treesRoot;
treesRoot = s.findMinHeightTrees(n, edges);
for (unsigned i = 0; i < treesRoot.size(); i++)
cout << treesRoot[i] << " ";
cout << endl;
return 0;
}