[各种面试题] 树的最小高度

题目描述:

给定一棵无向树, 我们选择不同的节点作为根节点时,可以得到不同的高度(即树根节点到叶子节点距离的最大值), 现在求这棵树可能的最低高度。

输入:

输入可能包含多个测试案例。
对于每个测试案例,输入的第一行为一个整数n(1 <= n <= 1000000)。
接下n-1行,每行包括两个整数u,v( 0<= u,v < n)代表这棵树的一个边连接的两个顶点。

输出:

对应每个测试案例,输出这棵树可能的最小高度。

样例输入:
3
0 1
1 2
5
0 1
1 2
1 3
1 4
样例输出:
1
1

我印象中这好像是谷歌某一年的笔试题吧。

我的思路就是求这个图中的最长路径,然后很明显要得到最小高度,那么树根肯定是这个最长路径的中间节点作为根,但是注意这条最长路径为奇数和为偶数的处理哦。也就是最后还剩一个节点或者两个节点的情况,如果只剩一个节点,那好,它就是根了呗,如果是两个节点,那么两个节点都可以作为根,并且最后的高度要加一。

#include<iostream>
#include<cstdio>
#include<vector>
#include<string>
#include<cstring>
#include<climits>
#include<queue>
#include<map>
#include<algorithm>
using namespace std;

const int MAXN=1000005;
vector<int> adj[MAXN];
vector<int> indegree(MAXN);

int main()
{
	int n;
	while(scanf("%d",&n)!=EOF)
	{
		for(int i=0;i<n;i++)
		{
			indegree[i]=0;
			adj[i].clear();
		}
		for(int i=0;i<n-1;i++)
		{
			int a,b;
			scanf("%d%d",&a,&b);
			adj[a].push_back(b);
			adj[b].push_back(a);
			indegree[a]++;
			indegree[b]++;
		}
		int cnt=n;
		queue<int> Q;
		for(int i=0;i<n;i++)
			if(indegree[i]==1)
			{
				Q.push(i);
				cnt--;
			}
		int len=0;
		
		while(!Q.empty())
		{
			len++;
			if(cnt<=2)
				break;
			int k=Q.size();
			while(k--)
			{
				int t=Q.front();
				Q.pop();
				for(int i=0;i<adj[t].size();i++)
					if(--indegree[adj[t][i]]==1)
					{
						Q.push(adj[t][i]);
						cnt--;
					}
			}
			
		}
		if(cnt==1)
			printf("%d\n",len);
		else
			printf("%d\n",len+1);
	}
}

然后求最长路径还可以转换为这样: 任意找一个点作为根(注意是多叉树不是二叉树哦),然后就跟这个一样了,只是边的权值都是1

http://blog.csdn.net/a83610312/article/details/11786571,就是说这个最长路径要么是某个孩子里的一个最长路径,要么是从某个孩子穿过自己在链接到另一个孩子去。

思路就是这样,各位有兴趣自己再实现一下。

然后再推荐一个别人的DP解法,我自己也还没看懂。。。

http://t.jobdu.com/thread-101867-1-1.html


另外还有个非常棒的方法: 是做两次BFS,来自:http://eriol.iteye.com/blog/1171820

还有一个利用拓扑排序来做DP的,也很巧妙:http://www.cnblogs.com/yanlingyin/archive/2011/11/12/2246716.html

你可能感兴趣的:([各种面试题] 树的最小高度)