PAT Advanced A1021 Deepest Root (25) [图的遍历,DFS,计算连通分量的个数,BFS,并查集]
题目
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 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
题目分析
已知图的顶点N和边N-1,判断所给图是否是一棵树,如果是,查找并打印最高树的所有根节点(从小到大)
- 判断图为树有两个条件:只有一个连通分量(否则为森林);无环(已知顶点数为N,边为N-1的连通图一定是树)
- 最高树的所有根节点,其含义可以从样例中推导得出(起始顶点不同,寻找出的最高树不同)

解题思路
1. 存储顶点和边
- 邻接表
- 邻接矩阵
2. 计算连通分量个数
连通分量等于1时,满足条件
- DFS
- BFS
- 并查集
3. 查找最大高度树的根节点
- 任意取一个顶点,求其能到达的最远的节点集合A,如测试样例1中:取1,可以得到5,3,4
- 任取取A集合中一个顶点,求其能到达的最远的节点集合B,如取A集合中3,可以得到4,5
- 集合A和集合B的并集去重排序,即为答案
Code
Code 01(邻接矩阵 并查集)
#include <iostream>
#include <vector>
#include <set>
using namespace std;
const int maxn=10010;
vector<int> g[maxn],temp; //邻接表 存储边
set<int> vs; // 存储所有满足条件的 the deepest roots
int maxh,n,father[maxn],vis[maxn];
/*
并查集判断连通分量树
两次dfs求the deepest root
*/
int init() { /* 并查集 初始化 */
for(int i=1; i<=n; i++)father[i]=i;
}
int find(int x) { /* 并查集 查 */
int a = x;
while(x!=father[x]) {
x=father[x];
}
while(a!=father[a]) { // 路径压缩
int temp=a;
a=father[a];
father[a]=x;
}
return x;
}
void Union(int a,int b) { /* 并查集 并 */
int fa=find(a);
int fb=find(b);
if(fa<fb)father[fb]=fa;
else father[fa]=fb;
}
void dfs(int a, int h) { /* dfs */
vis[a]=1;
if(h>maxh) {
temp.clear();
temp.push_back(a); // the deepest root
maxh=h;
} else if(h==maxh)
temp.push_back(a);
for(int i=0; i<g[a].size(); i++) {
if(vis[g[a][i]]==0)
dfs(g[a][i],h+1);
}
}
void pts() {
for(int i=0; i<temp.size(); i++)
vs.insert(temp[i]);
}
int main(int argc,char * argv[]) {
int a,b;
scanf("%d",&n);
init();
for(int i=1; i<=n-1; i++) {
scanf("%d %d",&a,&b);
g[a].push_back(b);
g[b].push_back(a);
Union(a,b);
}
// 统计连通分量数
for(int i=1; i<=n; i++) {
vs.insert(find(i));
}
if(vs.size()>1) {
printf("Error: %d components",vs.size());
return 0;
}
vs.clear(); //vs重置,方便下面使用
dfs(1,1); // 第一次dfs,任意取一个顶点,获取最深根集合A
pts(); //将集合A存入set
fill(vis,vis+maxn,0); //重置vis访问标记数组
//maxh=0; //无需重置maxh,因为第一轮得到的maxh即为最高树高度,第二轮中h==maxh时添加剩余的the deepest root
dfs(temp[0],1);// 第二次dfs,从集合A中任取一个顶点,获取最深根集合B
pts(); //将集合B存入set
for(set<int>::iterator it=vs.begin(); it!=vs.end(); it++) { //set默认从小到大,A+B去重即为结果
printf("%d\n",*it);
}
return 0;
}
Code 02(邻接矩阵 DFS)
#include <iostream>
#include <vector>
#include <set>
using namespace std;
const int maxn=10010;
vector<int> g[maxn],temp; //邻接表 存储边
set<int> vs; // 存储所有满足条件的 the deepest roots
int n,maxh,vis[maxn];
/*
第一次dfs 求连通分量,求the deepest root集合A
第二次dfs 求the deepest root集合B
集合A+B,去重排序 即为答案
*/
void dfs(int a, int h) { /* dfs */
vis[a]=1;
if(h>maxh) {
temp.clear();
temp.push_back(a); // the deepest root
maxh=h;
} else if(h==maxh)
temp.push_back(a);
for(int i=0; i<g[a].size(); i++) {
if(vis[g[a][i]]==0)
dfs(g[a][i],h+1);
}
}
void pts() {
for(int i=0; i<temp.size(); i++)
vs.insert(temp[i]);
}
int main(int argc,char * argv[]) {
int a,b;
scanf("%d",&n);
for(int i=1; i<=n-1; i++) {
scanf("%d %d",&a,&b);
g[a].push_back(b);
g[b].push_back(a);
}
// 统计连通分量数
int cnt=0;
for(int i=1; i<=n; i++) {
if(vis[i]==0){
dfs(i,0);
pts(); //将集合A存入set
cnt++;
}
}
if(cnt>1) {
printf("Error: %d components",cnt);
return 0;
}
fill(vis,vis+maxn,0); //重置vis访问标记数组
//maxh=0; //无需重置maxh,因为第一轮得到的maxh即为最高树高度,第二轮中h==maxh时添加剩余的the deepest root
dfs(temp[0],1);// 第二次dfs,从集合A中任取一个顶点,获取最深根集合B
pts(); //将集合B存入set
for(set<int>::iterator it=vs.begin(); it!=vs.end(); it++) { //set默认从小到大,A+B去重即为结果
printf("%d\n",*it);
}
return 0;
}
Code 03(邻接矩阵 BFS)
#include <iostream>
#include <vector>
#include <set>
#include <queue>
using namespace std;
const int maxn=10010;
vector<int> g[maxn],temp; //邻接表 存储边
set<int> vs; // 存储所有满足条件的 the deepest roots
int n,maxh,vis[maxn];
struct node {
int v;
int h;
};
/*
第一次bfs 求连通分量,求the deepest root集合A
第二次bfs 求the deepest root集合B
集合A+B,去重排序 即为答案
*/
void bfs(int a) { /* dfs */
vis[a]=1;
queue<node> q;
q.push({a,0});
while(!q.empty()) {
node now = q.front();
q.pop();
if(now.h>maxh) {
temp.clear();
temp.push_back(now.v); // the deepest root
maxh=now.h;
} else if(now.h==maxh)
temp.push_back(now.v);
for(int i=0; i<g[now.v].size(); i++)
if(vis[g[now.v][i]]==0){
q.push({g[now.v][i],now.h+1});
vis[g[now.v][i]]=1;
}
}
}
void pts() {
for(int i=0; i<temp.size(); i++)
vs.insert(temp[i]);
}
int main(int argc,char * argv[]) {
int a,b;
scanf("%d",&n);
for(int i=1; i<=n-1; i++) {
scanf("%d %d",&a,&b);
g[a].push_back(b);
g[b].push_back(a);
}
// 统计连通分量数
int cnt=0;
for(int i=1; i<=n; i++) {
if(vis[i]==0) {
bfs(i);
pts(); //将集合A存入set
cnt++;
}
}
if(cnt>1) {
printf("Error: %d components",cnt);
return 0;
}
fill(vis,vis+maxn,0); //重置vis访问标记数组
//maxh=0; //无需重置maxh,因为第一轮得到的maxh即为最高树高度,第二轮中h==maxh时添加剩余的the deepest root
bfs(temp[0]);// 第二次dfs,从集合A中任取一个顶点,获取最深根集合B
pts(); //将集合B存入set
for(set<int>::iterator it=vs.begin(); it!=vs.end(); it++) //set默认从小到大,A+B去重即为结果
printf("%d\n",*it);
return 0;
}
Code 04(邻接表 DFS)
#include <iostream>
#include <vector>
#include <set>
using namespace std;
const int maxn=10010;
vector<int> temp; //邻接表 存储边
set<int> vs; // 存储所有满足条件的 the deepest roots
int n,maxh,vis[maxn],g[maxn][maxn];
/*
第一次dfs 求连通分量,求the deepest root集合A
第二次dfs 求the deepest root集合B
集合A+B,去重排序 即为答案
*/
void dfs(int a, int h) { /* dfs */
vis[a]=1;
if(h>maxh) {
temp.clear();
temp.push_back(a); // the deepest root
maxh=h;
} else if(h==maxh)
temp.push_back(a);
for(int i=1; i<maxn; i++)
if(g[a][i]==1 && vis[i]==0)
dfs(i,h+1);
}
void pts() {
for(int i=0; i<temp.size(); i++)
vs.insert(temp[i]);
}
int main(int argc,char * argv[]) {
int a,b;
scanf("%d",&n);
for(int i=1; i<=n-1; i++) {
scanf("%d %d",&a,&b);
g[a][b]=1;
g[b][a]=1;
}
// 统计连通分量数
int cnt=0;
for(int i=1; i<=n; i++) {
if(vis[i]==0) {
dfs(i,0);
pts(); //将集合A存入set
cnt++;
}
}
if(cnt>1) {
printf("Error: %d components",cnt);
return 0;
}
fill(vis,vis+maxn,0); //重置vis访问标记数组
//maxh=0; //无需重置maxh,因为第一轮得到的maxh即为最高树高度,第二轮中h==maxh时添加剩余的the deepest root
dfs(temp[0],1);// 第二次dfs,从集合A中任取一个顶点,获取最深根集合B
pts(); //将集合B存入set
for(set<int>::iterator it=vs.begin(); it!=vs.end(); it++) { //set默认从小到大,A+B去重即为结果
printf("%d\n",*it);
}
return 0;
}
Code 05(邻接表 BFS)
#include <iostream>
#include <vector>
#include <set>
#include <queue>
using namespace std;
const int maxn=10010;
vector<int> temp; //邻接表 存储边
set<int> vs; // 存储所有满足条件的 the deepest roots
int n,maxh,vis[maxn],g[maxn][maxn];
struct node {
int v;
int h;
};
/*
第一次bfs 求连通分量,求the deepest root集合A
第二次bfs 求the deepest root集合B
集合A+B,去重排序 即为答案
*/
void bfs(int a) { /* dfs */
vis[a]=1;
queue<node> q;
q.push({a,0});
while(!q.empty()) {
node now = q.front();
q.pop();
if(now.h>maxh) {
temp.clear();
temp.push_back(now.v); // the deepest root
maxh=now.h;
} else if(now.h==maxh)
temp.push_back(now.v);
for(int i=1; i<maxn; i++)
if(g[now.v][i]==1 && vis[i]==0){
q.push({i,now.h+1});
vis[i]=1;
}
}
}
void pts() {
for(int i=0; i<temp.size(); i++)
vs.insert(temp[i]);
}
int main(int argc,char * argv[]) {
int a,b;
scanf("%d",&n);
for(int i=1; i<=n-1; i++) {
scanf("%d %d",&a,&b);
g[a][b]=1;
g[b][a]=1;
}
// 统计连通分量数
int cnt=0;
for(int i=1; i<=n; i++) {
if(vis[i]==0) {
bfs(i);
pts(); //将集合A存入set
cnt++;
}
}
if(cnt>1) {
printf("Error: %d components",cnt);
return 0;
}
fill(vis,vis+maxn,0); //重置vis访问标记数组
//maxh=0; //无需重置maxh,因为第一轮得到的maxh即为最高树高度,第二轮中h==maxh时添加剩余的the deepest root
bfs(temp[0]);// 第二次dfs,从集合A中任取一个顶点,获取最深根集合B
pts(); //将集合B存入set
for(set<int>::iterator it=vs.begin(); it!=vs.end(); it++) //set默认从小到大,A+B去重即为结果
printf("%d\n",*it);
return 0;
}

PAT Advanced A1021 Deepest Root (25) [图的遍历,DFS,计算连通分量的个数,BFS,并查集]的更多相关文章
- PAT Advanced 1013 Battle Over Cities (25) [图的遍历,统计连通分量的个数,DFS,BFS,并查集]
题目 It is vitally important to have all the cities connected by highways in a war. If a city is occup ...
- PAT 甲级 1021 Deepest Root (25 分)(bfs求树高,又可能存在part数part>2的情况)
1021 Deepest Root (25 分) A graph which is connected and acyclic can be considered a tree. The heig ...
- PAT甲级——A1021 Deepest Root
A graph which is connected and acyclic can be considered a tree. The height of the tree depends on t ...
- PAT Advanced 1020 Tree Traversals (25) [⼆叉树的遍历,后序中序转层序]
题目 Suppose that all the keys in a binary tree are distinct positive integers. Given the postorder an ...
- PAT Advanced 1138 Postorder Traversal (25) [树的遍历,前序中序转后序]
题目 Suppose that all the keys in a binary tree are distinct positive integers. Given the preorder and ...
- [PAT] 1021 Deepest Root (25)(25 分)
1021 Deepest Root (25)(25 分)A graph which is connected and acyclic can be considered a tree. The hei ...
- PAT甲级1021. Deepest Root
PAT甲级1021. Deepest Root 题意: 连接和非循环的图可以被认为是一棵树.树的高度取决于所选的根.现在你应该找到导致最高树的根.这样的根称为最深根. 输入规格: 每个输入文件包含一个 ...
- PAT 甲级 1021 Deepest Root (并查集,树的遍历)
1021. Deepest Root (25) 时间限制 1500 ms 内存限制 65536 kB 代码长度限制 16000 B 判题程序 Standard 作者 CHEN, Yue A graph ...
- 图的遍历DFS
图的遍历DFS 与树的深度优先遍历之间的联系 树的深度优先遍历分为:先根,后根 //树的先根遍历 void PreOrder(TreeNode *R){ if(R!=NULL){ visit(R); ...
随机推荐
- SpringData JPA使用JPQL的方式查询和使用SQL语句查询
使用Spring Data JPA提供的查询方法已经可以解决大部分的应用场景,但是对于某些业务来说,我们还需要灵活的构造查询条件, 这时就可以使用@Query注解,结合JPQL的语句方式完成查询 持久 ...
- Java入门基础(类的方法)
方法 1.添加方法 方法表示一个类能做什么.在Java里,方法和属性属于对等的术语,在一个类中,不仅可以添加属性,还可以添加方法. 类 { 属性:描述“我有什么” 方法:描述“我能做什么” } 例子: ...
- Adapter之GridAdapter
前言: 在我们写界面的时候想让我们展示的页面是网格的,这是我们可以使用GridAdapter,这个和listView的使用有相似之处,如果学过ListView的话还是很简单的 正文: 下面我们来看看G ...
- Rolling Update【转】
滚动更新是一次只更新一小部分副本,成功后,再更新更多的副本,最终完成所有副本的更新.滚动更新的最大的好处是零停机,整个更新过程始终有副本在运行,从而保证了业务的连续性. 下面我们部署三副本应用,初始镜 ...
- 查看oracle单签session
转自 https://blog.csdn.net/alexsong123/article/details/51858092 怎样查看oracle当前的连接数呢?只需要用下面的SQL语句查询一下就可以了 ...
- Linux远程上传文件
#对拷文件夹 (包括文件夹本身) scp -r /home/slk root@192.168.1.5:/home # 对拷文件并重命名 scp /home/a.txt root@192.168.1.5 ...
- R语言 方差稳定化变换与线性变换 《回归分析与线性统计模型》page96
> rm(list = ls()) > A=read.csv("data96.csv") > A Y N 1 11 0.0950 2 7 0.1920 3 7 0 ...
- java随记 2月16
1.a=a+b 等于 a+=b ,且a+=b隐含强制类型转换 2.^ 表示异或 两个二进制同号为假,异号为真 即 0^0=0,1^1=0,0^1=1 3.三元运算 布尔表达式 ?表达式 ...
- mybatis-generator-plugin
1.背景 这篇文章刚开始想着哪个分类呢?mybatis.idea或是maven呢,最后还是选择了mybatis.最初使用这个逆向工具是在eclipse上,使用的是eclispe上mbg插件执行配置ge ...
- C++用sqlite3_open连接打开指定数据库的小问题
一开始我也纳闷,我以为是我数据库没弄好,但是当我仔细检查,才发现 原来我少了分号 写少了分号,可能会导致 database 和 table 找不到... 所以用的时候需要注意... 代 ...