题目链接
题目分析
1、判断图是否为一棵树,是则输出最深根,不是则输出连通块数
2、节点编号1-N
3、无向图
解题思路
(思路一:)
1、DFS判断 是否为一棵树
2、寻找最大根:暴力搜索
结点数10000,则两重循环复杂度会达到10^8量级,
时间限制为1500ms,1s内计算次数一般为10^7-10^8
,
提交发现,最大测试点花了将近1100ms,低空飞过!!
(思路二:)借鉴《算法笔记》
1、并查集判断是够是连通图
2、寻找最深根:进行两次DFS即可;
第一次任选一个结点作为根,找出它的最深叶节点(记为集合A);第二次以集合A中任一点作为根再找出最深叶节点(记为B);两次集合的并集即为最深根节点集合。
AC程序(C++)
思路(一)
/**********************************
*@Author: 3stone
*@ACM: PAT.A1021 Deepest Root
*@Time: 18/8/13
*@IDE: VSCode 2018 + clang++
***********************************/
#include<cstdio>
#include<vector>
#include<set>
using namespace std;
const int maxn = 10010;
int N; //结点数
vector<int> Adj[maxn]; //邻接表
bool vis[maxn]; //标记结点是够进入队列
set<int> deepest_root; //保存满足条件的根序号
//用于判断连通块的 DFS
void DFS(int u) {
vis[u] = true;
for(int i = 0; i < Adj[u].size(); i++){
if(vis[Adj[u][i]] == false) {
DFS(Adj[u][i]);
}
}
}
//DFS获取树的深度
void DFS_depth(int u, int &dep, int depth) {
vis[u] = true;
if(depth > dep)
dep = depth;
for(int i = 0; i < Adj[u].size(); i++) {
if(vis[Adj[u][i]] == false){
DFS_depth(Adj[u][i], dep, depth + 1);
}
}
}
int main() {
int node_a, node_b;
while(scanf("%d", &N) != EOF) {
for(int i = 1; i <= N; i++){ //初始化 均未访问
vis[i] = false;
Adj[i].clear(); //清空图
}
//输入图信息
for(int i = 1; i < N; i++) { //输入边的信息
scanf("%d%d", &node_a, &node_b);
//无向图
Adj[node_a].push_back(node_b);
Adj[node_b].push_back(node_a);
}
//判断是够为一棵树
int num = 0; //记录连通块数
for(int i = 1; i <= N; i++) {
if(vis[i] == false){
DFS(i);
num++;
}
}
if(num > 1) { //多个连通块
printf("Error: %d components\n", num);
}
else { //形成一棵树
//printf("I am a tree!\n");
//(法一):暴力搜索:结点数10000,则复杂度会达到10^8量级,
//时间限制为1500ms,1s内计算次数一般为10^7-10^8,
//提交发现,最大测试点花了将近1100ms,低空飞过!!
int dep, mx_dep = 0;
deepest_root.clear();
for(int i = 1; i <= N; i++) {
for(int j = 1; j <= N; j++) //初始化 均未访问
vis[j] = false;
dep = 0;
DFS_depth(i, dep, 1);
if(dep == mx_dep){
deepest_root.insert(i);
}
else if(dep > mx_dep) { //发现更深的树
mx_dep = dep;
deepest_root.clear();
deepest_root.insert(i);
}
}
//输出树根
set<int>::iterator it, st_end = deepest_root.end();
for(it = deepest_root.begin(); it != st_end; it++) {
printf("%d\n", *it);
}
//(法二):并查集可以操作吗??
}//else-成树
}//while
return 0;
}
思路(二):并查集+DFS
1、并查集判断是够是连通图
2、寻找最深根:进行两次DFS即可;
第一次任选一个结点作为根,找出它的最深叶节点(记为集合A);第二次以集合A中任一点作为根再找出最深叶节点(记为B);两次集合的并集即为最深根节点集合。
/**********************************
*@Author: 3stone
*@ACM: PAT.A1021 Deepest Root
*@Time: 18/8/13
*@IDE: VSCode 2018 + clang++
***********************************/
#include<cstdio>
#include<set>
#include<vector>
#include<algorithm>
using namespace std;
const int maxn = 10010;
int N;
int farther[maxn];
vector<int> A, B;
set<int> root_set;
vector<int> Adj[maxn];
bool vis[maxn];
int max_dep;
//并查集初始化
void init() {
for(int i = 1; i <= N; i++)
farther[i] = i;
}
//寻根
int find_root(int a) {
int root = a;
while(root != farther[root])
root = farther[root];
while (a != farther[a]) {
int cur = a;
a = farther[a];
farther[cur] = root;
}
return root;
}
void union_set(int a, int b) {
a = find_root(a);
b = find_root(b);
if(a != b)
farther[b] = a;
}
void dfs_find(int v, int depth) {
vis[v] = true;
depth++;
if(depth > max_dep) {
A.clear();
A.push_back(v);
max_dep = depth;
} else if(depth == max_dep){
A.push_back(v);
}
for(int i = 0; i < Adj[v].size(); i++){
if(vis[Adj[v][i]] == false)
dfs_find(Adj[v][i], depth);
}
}
int main() {
int a, b;
while(scanf("%d", &N) != EOF) {
if(N == 1) {
printf("1\n");
continue;
}
for(int i = 1; i <= N; i++) //清空图
Adj[i].clear();
fill(vis, vis + maxn, false);
init();
for(int i = 0; i < N-1; i++){
scanf("%d%d", &a, &b);
Adj[a].push_back(b);
Adj[b].push_back(a);
union_set(a, b);
}
//检查是否是连通图(即只有一个集合)
int set_num = 0;
for(int i = 1; i <= N; i++){
if(i == farther[i])
set_num++;
}
if(set_num > 1) {
printf("Error: %d components\n", set_num);
continue;
}
A.clear();
max_dep = 0;
//找到集合A
dfs_find(1, 0);
for(int i = 0; i < A.size(); i++)
root_set.insert(A[i]);
int temp = A[0];
fill(vis, vis + maxn, false);
max_dep = 0;
A.clear();
//找到集合B
dfs_find(temp, 0);
for(int i = 0; i < A.size(); i++)
root_set.insert(A[i]);
for(set<int>::iterator it = root_set.begin(); it != root_set.end(); it++) {
printf("%d\n", *it);
}
}
return 0;
}