-
题目描述:
-
给定一棵无向树, 我们选择不同的节点作为根节点时,可以得到不同的高度(即树根节点到叶子节点距离的最大值), 现在求这棵树可能的最低高度。
-
输入:
-
输入可能包含多个测试案例。
对于每个测试案例,输入的第一行为一个整数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