310. Minimum Height Trees

本题给出一个有树性质的无向图,可以选择任何一个点做树根,要求在所有可能性中,找出树高最小的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;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值