目次に戻る
タイトル
n個のノードとn-1個のエッジを与える。nノードのツリーを形成できるかどうか尋ねますか?可能であれば、出力ノードがツリーのルートとして使用されるため、ツリーの高さが最大化され、満たされたすべてのノードが出力されます。そうでない場合は、接続されているブロックの数が出力されます。
サンプル(コピー可能)
5
1 2
1 3
1 4
2 5
//output
3
4
5
5
1 3
1 4
2 5
3 4
//output
Error: 2 components
注意点
- この問題を解決するには、2つの問題があります:①ツリーを形成できるかどうかを決定する②ツリーを形成できるときの条件を満たすノードを見つける
- ①の問題については、チェックセットやDFSの方法で接続ブロック数を求めることができますが、block = 1の場合はツリーを形成することができます。この質問では、DFS方式を使用しています。
- 問題2には2つの解決策があります。1つ目は、任意のノードの最も遠いノードのセットAを見つけ、Aのノードを選択して、最も遠いノードのセットBを見つけます。AとBの和集合は、条件を満たすすべてのノードはここでは省略されます。このメソッドを使用してコレクションを使用する場合、結合する関数set_union()を含むSTLライブラリセットを使用できます。次に、各ノードをルートノードとして使用する場合のツリーの最大の高さを見つけ、最後に最大の高さを比較して、条件を満たすノードを取得します。この質問では後者を使用します。
#include<bits/stdc++.h>
using namespace std;
const int N=100010;
vector<int> G[N];
bool flag[N]={false};//标记节点是否访问过
int n,block=0;//节点数,连通块数
int maxdepth[N],depth[N];//maxdepth记录每个节点的最大深度,depth记录到root的距离
void DFS(int v,int root){
flag[v]=true;
for(int i:G[v]){
if(!flag[i]){
depth[i]=depth[v]+1;//当前结点深度为其父节点深度+1
maxdepth[root]=max(maxdepth[root],depth[i]);//更新树的深度
DFS(i,root);
}
}
}
int main(){
cin>>n;
int a,b;
for(int i=1;i<n;i++){//输入n-1条边
scanf("%d %d",&a,&b);
G[a].push_back(b);
G[b].push_back(a);
}
for(int i=1;i<=n;i++){
if(!flag[i]){
DFS(i,i);
block++;
}
}
if(block>1){
printf("Error: %d components\n",block);
}else{
for(int i=2;i<=n;i++){//i=1必然遍历过了
memset(depth,0,sizeof(depth));
memset(flag,false,sizeof(flag));
DFS(i,i);
}
vector<int> ans;//存储为根节点时使树的深度最大的结点
int deep=0;//查找所有为根节点时使树的深度最大的结点
for(int i=1;i<=n;i++)
if(maxdepth[i]>deep){
ans.clear();
ans.push_back(i);
deep=maxdepth[i];
}else if(maxdepth[i]==deep)
ans.push_back(i);
for(int i:ans)printf("%d\n",i);
}
return 0;
}