A graph which is connected and acyclic can be considered a tree. The height of the tree depends on the selected root. Now you are supposed to find the root that results in a highest tree. Such a root is called the deepest root.
翻译:一个连通的无环图可以看作是一棵树。树的高度取决于选定的根。现在你应该找到一棵最高的树的根。这样的根叫做最深根。
Input Specification:
Each input file contains one test case. For each case, the first line contains a positive integer N (≤104 ) which is the number of nodes, and hence the nodes are numbered from 1 to N. Then N−1 lines follow, each describes an edge by given the two adjacent nodes’ numbers.
翻译:每个输入文件包含一个测试用例。对于每种情况,第一行包含一个正整数N(≤104),这是节点的数目,因此节点编号从1到N。然后N−1行,每行通过给定两个相邻节点的编号来描述一条边。
Output Specification:
For each test case, print each of the deepest roots in a line. If such a root is not unique, print them in increasing order of their numbers. In case that the given graph is not a tree, print Error: K components
where K is the number of connected components in the graph.
翻译:对于每个测试用例,将每个最深的根打印在一行中。如果这样的根不是唯一的,请按数字的递增顺序打印。如果给定的图不是树,则打印Error: K components
,其中K是图中连通块个数。
Sample Input 1:
5
1 2
1 3
1 4
2 5
Sample Output 1:
3
4
5
Sample Input 2:
5
1 3
1 4
2 5
3 4
Sample Output 2:
Error: 2 components
思路
刚开始看到要求连通块数和树的高度,第一反应就是用DFS求解。这里确实也是用DFS,求出了图中最高的树的高度和连通块树,但接下来在如何用递归来记录当高度和最高高度一样时的根结点上犯了难…思考了很久发现自己陷入了思维定势,我总感觉根是1。但其实题目已经暗示我们了树的高度取决于选定的根,也就是说这棵树在不停的变化根结点,然后根据当前的根结点求高度,比如样例1:
1 3 4
/ | \ __以3为根变成这样____ | __以4为根__ |
2 3 4 1 1
\ / \ / \
5 2 4 2 3
| |
5 5
这样想的话就可以直接用BFS求层数的方法,当某个点为根时,直接求它的高度就行了!
于是我的思路就变成了,利用DFS求出最高的高度以及连通块数,再使用BFS对每个点,求它作为根结点时的高度。当高度等于最高高度时,加入vector容器,最后让容器内元素排序输出。但是我写的代码测试点3超时,测试点5错误,只拿了22分,代码如下
22分做法
#include <iostream>
#include <cstdlib>
#include <vector>
#include <queue>
#include <map>
#include <algorithm>
using namespace std;
vector<int> G[10002];
map<int, bool> visit; //visit用来记录结点访问情况
map<int, bool> visit2; //visit2用来判断连通块个数
int block = 0, max_height = 0, n;
void dfs_trav();
void dfs(int, int);
int get_height(int);
int main()
{
cin >> n;
for (int i = 0; i < n - 1; i++)
{
int node1, node2;
cin >> node1 >> node2;
G[node1].push_back(node2);
G[node2].push_back(node1);
}
dfs_trav();
if (block > 1)
cout << "Error: " << block << " components";
else
{
vector<int> vec;
//一个一个判断是否等于最高高度
for (int i = 1; i <= n; i++)
if (get_height(i) == max_height)
vec.push_back(i);
sort(vec.begin(), vec.end()); //排序
for (int i = 0; i < vec.size(); i++)
cout << vec[i] << endl;
}
system("pause");
return 0;
}
void dfs_trav()
{
for (int i = 1; i <= n; i++)
{
visit.clear();
if (visit2[i] == false)
block++; //记录连通块数
dfs(i, 1);
}
}
void dfs(int v, int h)
{
if (h > max_height)
max_height = h;
visit[v] = true;
visit2[v] = true;
for (int i = 0; i < G[v].size(); i++)
if (visit[G[v][i]] == false)
dfs(G[v][i], h + 1);
}
int get_height(int v)
{
//利用队列实现层序遍历
int level = 0;
map<int, bool> vis;
queue<int> que;
que.push(v);
vis[v] = true;
while (!que.empty())
{
level++;
for (int i = 0; i < que.size(); i++)
{
int top = que.front();
for (int j = 0; j < G[top].size(); j++)
{
//这里一定要判断是否访问过,因为是无向图
//如果不加以判断,比如样例1,结点1时将2加入队列,后面结点2时又会将1加入队列
if (vis[G[top][j]] == false)
que.push(G[top][j]);
vis[G[top][j]] = true;
}
que.pop();
}
}
return level;
}
ps:写这段代码也让我发现我对DFS理解不够深入,以及层序遍历编写不够熟练(编的时候网上搜了不少次)建议多加练习。
后来想通了如何用递归来记录当高度和最高高度一样时的根结点。定义一个数组用来记录每个结点的深度,然后重新写一个dfs,每次记录一个结点的最高高度。这个做法阴差阳错的解决了测试点5(但目前还是不知道为什么22分做法测试点5会错),现在只剩超时的测试点3了。
23分做法
#include <iostream>
#include <cstdlib>
#include <vector>
#include <map>
using namespace std;
vector<int> G[10002];
int depth[10001];
map<int, bool> visit;
map<int, bool> visit2;
int block = 0, max_height = 0, n;
void dfs_trav();
void dfs(int, int);
void dfs_getheight(int, int&, int); //用来求高度
int main()
{
cin >> n;
for (int i = 0; i < n - 1; i++)
{
int node1, node2;
cin >> node1 >> node2;
G[node1].push_back(node2);
G[node2].push_back(node1);
}
dfs_trav();
if (block > 1)
cout << "Error: " << block << " components";
else
{
for (int i = 1; i <= n; i++)
{
int d = 0, h = 1;
visit.clear();
dfs_getheight(i, d, h);
depth[i] = d;
}
for (int i = 1; i <= n; i++)
if (depth[i] == max_height)
cout << i << endl;
}
system("pause");
return 0;
}
void dfs_trav()
{
for (int i = 1; i <= n; i++)
{
visit.clear();
if (visit2[i] == false)
block++; //记录连通块数
dfs(i, 1);
}
}
void dfs(int v, int h)
{
if (h > max_height)
max_height = h;
visit[v] = true;
visit2[v] = true;
for (int i = 0; i < G[v].size(); i++)
if (visit[G[v][i]] == false)
dfs(G[v][i], h + 1);
}
void dfs_getheight(int v, int& depth, int h)
{
if (h > depth)
depth = h; //depth用来记录该结点v的最高高度,必须是引用类型
visit[v] = true;
for (int i = 0; i < G[v].size(); i++)
if (visit[G[v][i]] == false)
dfs_getheight(G[v][i], depth, h + 1);
}