Minimum Height Trees


For a undirected graph with tree characteristics, we can choose any node as the root. The result graph is then a rooted tree. Among all possible rooted trees, those with minimum height are called minimum height trees (MHTs). Given such a graph, write a function to find all the MHTs and return a list of their root labels.

Format
The graph contains n nodes which are labeled from 0 to n - 1. You will be given the number n and a list of undirected edges (each edge is a pair of labels).

You can assume that no duplicate edges will appear in edges. Since all edges are undirected, [0, 1] is the same as [1, 0] and thus will not appear together in edges.

Example 1:

Given n = 4, edges = [[1, 0], [1, 2], [1, 3]]

        0
        |
        1
       / \
      2   3

return [1]

Example 2:

Given n = 6, edges = [[0, 3], [1, 3], [2, 3], [4, 3], [5, 4]]

     0  1  2
      \ | /
        3
        |
        4
        |
        5

return [3, 4]

Hint:

Show Hint
  1. How many MHTs can a graph have at most?

Note:

(1) According to the definition of tree on Wikipedia: “a tree is an undirected graph in which any two vertices are connected by exactly one path. In other words, any connected graph without simple cycles is a tree.”

(2) The height of a rooted tree is the number of edges on the longest downward path between the root and a leaf.

题目的大意是给定一棵树,一棵树的根节点是可以随意指定的,题目要求我们找出使得树的高度最小的根节点的集合。

解这道题目的方法是每次都去掉树中的所有叶子节点,这样逐层地去除叶子节点,那么最后一层的结点就是使得树的高度最小的根节点。

对于上述结论,我在这里做一个简单的证明,如果我们按照去除结点的顺序给所有结点分层,最后去除的结点在第一层,最早去除的结点在最后一层,所以度数为1的点一定在最后一层中,也就是说所以叶子结点都在最后一层,假设以非第一层的结点作为根节点使得树的高度比当前的高度小,我们不妨假设这个结点在根节点偏左侧的分支中,如果树的高度比原来的小,也就是说根节点右侧的分支的高度是小于原来的高度的,也就是说右侧分支的叶结点不在最后一层,这与上述结论矛盾。

具体的算法是根据边集计算每个顶点的度数,并存在向量d中,并且用二维向量g建立一个邻接表,对于每个结点,把与它邻接的所有点都保存在向量中,然后就开始逐层地删除结点,每次都判断每个结点的度数是否为1或0(度数为0却还没有被删除的情况只有在只剩一个顶点的情况下出现),如果是就删除改点,并把同一层的所有结点都放在向量result中,而为了标记改点已经被删除,要把它的度数设为-1,在把同一层的叶子结点都删除以后,再逐个点地删除它们对应的边,按照这样的方法循环操作,循环的结束条件是所有点都已经被删除,而为了简化判断操作,我用delnum记录当前已经被删的结点数,也就是说只要delnum的值等于n就可以停止循环了。而最后的答案就是最后一层的结点,这些结点都保存在向量result中,

计算这个算法的时间复杂度比较困难,在while循环中的第一个for循环的复杂度是节点数乘以树的高度,也就是O(V*logV),第二个for循环是每条边都遍历两次,也就是O(E),由于这个图是一棵树,所以时间复杂度应该是O(V*logV)。

以下为源程序:

(n);
        int delnum=0;
        for(int i=0;i<edges.size();i++)
        {
            g[edges[i].first].push_back(edges[i].second);
            g[edges[i].second].push_back(edges[i].first);
            d[edges[i].first]++;
            d[edges[i].second]++;
        }
        vector<int> result;
        while(delnum<n)
        {
            result.clear();
            for(int i=0;i<n;i++)
                if(d[i]==1||d[i]==0)
                {
                    d[i]=-1;
                    delnum++;
                    result.push_back(i);
                }
            for(int i=0;i<result.size();i++)
            {
                for(int j=0;j<g[result[i]].size();j++)
                    if(d[g[result[i]][j]]!=-1) 
                        d[g[result[i]][j]]--;
            }
        }
        return result;
    }
};


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值