PAT甲级练习1021. Deepest Root (25)

来源:互联网 发布:算法导论22章 编辑:程序博客网 时间:2024/06/05 10:46

1021. Deepest Root (25)

时间限制
1500 ms
内存限制
65536 kB
代码长度限制
16000 B
判题程序
Standard
作者
CHEN, Yue

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:
51 21 31 42 5
Sample Output 1:
345
Sample Input 2:
51 31 42 53 4
Sample Output 2:
Error: 2 components
计算最长深度的问题,觉得可以用dfs来做,但是也想到会有超时的问题,因为没有终点,且对每个起点需要全部遍历,并且也不像算最小距离时可以剪枝减少运算。做完之后结果也证实了有一个节点运行超时。。

#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部分正确231021C++ (g++ 4.7.2)73840shower

测试点

测试点结果用时(ms)内存(kB)得分/满分0答案正确438413/131答案正确43842/22答案正确738405/53运行超时  0/24答案正确44322/25答案正确43841/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答案正确251021C++ (g++ 4.7.2)28940704shower

测试点

测试点结果用时(ms)内存(kB)得分/满分0答案正确1638413/131答案正确72842/22答案正确1638405/53答案正确289407042/24答案正确163842/25答案正确93841/1


0 0
原创粉丝点击