1021. Deepest Root (25)
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 (<=10000) 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.
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.
Sample Input 1:5 1 2 1 3 1 4 2 5Sample Output 1:
3 4 5Sample Input 2:
5 1 3 1 4 2 5 3 4Sample Output 2:
Error: 2 components
#include <iostream>
#include <cmath>
#include <algorithm>
#include <vector>
#include <string>
using namespace std;
int n, x, y, num=0;
int maxDepth=0, tmp=0;
int r[10001][10001];
bool visited[10001];
vector<int> lroot;
void dfs2(int x, int length){//计算长度
visited[x] = true;
if(length>tmp){
tmp = length;
}
for(int i=1; i<=n; i++){
if(visited[i]==false && r[x][i]==1){
dfs2(i,length+1);
}
}
visited[x] = false;
}
void dfs1(int x){//判断是否只有一个连通域
visited[x] = true;
for(int i=1; i<=n; i++){
if(visited[i]==false && r[x][i]==1){
dfs1(i);
}
}
}
int main(){
scanf("%d", &n);
for(int i=1; i<=n-1; i++){
scanf("%d %d", &x, &y);
r[x][y] = r[y][x] = 1;
}
for(int i=1; i<=n; i++){
if(visited[i]==0){
num++;
dfs1(i);
}
}
memset(visited, false, 10001);
if(num>1){
printf("Error: %d components", num);
}else{
for(int i=1; i<=n; i++){
tmp=0;
dfs2(i, 0);
if(tmp>maxDepth){
maxDepth = tmp;
vector<int> y;
lroot.swap(y);
lroot.push_back(i);
}else if(tmp==maxDepth){
lroot.push_back(i);
}
}
}
for(int i=0; i<lroot.size(); i++){
printf("%d\n", lroot[i]);
}
cin>>n;
return 0;
}
评测结果
时间 | 结果 | 得分 | 题目 | 语言 | 用时(ms) | 内存(kB) | 用户 |
---|---|---|---|---|---|---|---|
2月18日 22:21 | 部分正确 | 23 | 1021 | C++ (g++ 4.7.2) | 7 | 3840 | shower |
测试点
测试点 | 结果 | 用时(ms) | 内存(kB) | 得分/满分 |
---|---|---|---|---|
0 | 答案正确 | 4 | 384 | 13/13 |
1 | 答案正确 | 4 | 384 | 2/2 |
2 | 答案正确 | 7 | 3840 | 5/5 |
3 | 运行超时 | 0/2 | ||
4 | 答案正确 | 4 | 432 | 2/2 |
5 | 答案正确 | 4 | 384 | 1/1 |
看了一下别人的做法,发现一个有趣的证明:树的直径(最长路)的证明。即从随便一点出发,通过dfs找到最远的节点,再从这一点出发进行dfs即可找到该树中距离最远的点。相关证明可以看看
判断完连通域个数后,可以从任一点开始dfs一遍获得一个最远点的集合,在从该集合中任选一点再dfs一遍即可得到另一组集合,然后合并这两个就是所得的最长的点的集合。注意第二遍不需要对第一遍得到的集合中每一个都去dfs一遍。
#include <iostream>
#include <cmath>
#include <algorithm>
#include <vector>
using namespace std;
int n, x, y, num=0;
int maxDepth=0, tmp=0;
int r[10001][10001];
bool visited[10001];
vector<int> lroot;
void dfs2(int x, int length){//计算长度
visited[x] = true;
if(length>maxDepth){
maxDepth = length;
vector<int> y;
lroot.swap(y);
lroot.push_back(x);
}else if(length==maxDepth){
lroot.push_back(x);
}
for(int i=1; i<=n; i++){
if(visited[i]==false && r[x][i]==1){
dfs2(i,length+1);
}
}
//visited[x] = false;
}
void dfs1(int x){//判断是否只有一个连通域
visited[x] = true;
for(int i=1; i<=n; i++){
if(visited[i]==false && r[x][i]==1){
dfs1(i);
}
}
}
int main(){
scanf("%d", &n);
for(int i=1; i<=n-1; i++){
scanf("%d %d", &x, &y);
r[x][y] = r[y][x] = 1;
}
for(int i=1; i<=n; i++){
if(visited[i]==0){
num++;
dfs1(i);
}
}
fill(visited, visited+10001, false);
if(num>1){
printf("Error: %d components", num);
}else{
visited[1] = true;
dfs2(1, 0);
vector<int> v1(lroot);
//int k=lroot.size();//不需要每个都去dfs一遍
//for(int i=0; i<k; i++){
// fill(visited, visited+10001, false);
// visited[lroot[i]] = true;
// dfs2(lroot[i], 0);
//}
fill(visited, visited+10001, false);
dfs2(lroot[0], 0);
v1.insert(v1.end(), lroot.begin(), lroot.end());
sort(v1.begin(), v1.end());
tmp = -1;
for(int i=0; i<v1.size(); i++){
if(v1[i]!=tmp){
printf("%d\n", v1[i]);
tmp = v1[i];
}
}
}
cin>>n;
return 0;
}
评测结果
时间 | 结果 | 得分 | 题目 | 语言 | 用时(ms) | 内存(kB) | 用户 |
---|---|---|---|---|---|---|---|
2月19日 14:05 | 答案正确 | 25 | 1021 | C++ (g++ 4.7.2) | 289 | 40704 | shower |
测试点
测试点 | 结果 | 用时(ms) | 内存(kB) | 得分/满分 |
---|---|---|---|---|
0 | 答案正确 | 16 | 384 | 13/13 |
1 | 答案正确 | 7 | 284 | 2/2 |
2 | 答案正确 | 16 | 3840 | 5/5 |
3 | 答案正确 | 289 | 40704 | 2/2 |
4 | 答案正确 | 16 | 384 | 2/2 |
5 | 答案正确 | 9 | 384 | 1/1 |