判断图是否连通+判断图是否有环+并集得到最深叶节点 1021 Deepest Root (25分)

25 篇文章 0 订阅
23 篇文章 0 订阅

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 (≤10
​4
​​ ) 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

解题
给定一个图,判断图中可使数高度最长的根节点,且判断图是否连通+有无环;

判断连通: dfs遍历一个结点后,查看有无未遍历的结点,遍历后继续查看,即可算出连通子图个数;
判断环: 若连通,则边个数为N-1说明无环,若边个数为N-1,有K个最大连通子图即有K-1个环;

解法1:暴力法
对每个结点进行dfs,记录dfs高度最大的结点,且每次dfs后做连通判断;

1.输入函数,建图

#include<iostream>
#include<vector> 
#include<algorithm>
using namespace std;

int N;
//若不连通,写出有几个子图
vector<vector<int>> Graph; 


void input()
{
	cin>>N;
	Graph.resize(N+1);
	int a,b;
	for(int i=0;i<N-1;i++)
	{
		cin>>a>>b;
		Graph[a].push_back(b);
		Graph[b].push_back(a);
	}	
 } 

2.dfs函数
遍历每个点,同时统计最高高度;

void dfs(int n,vector<int> &visited,int t)  //遍历的点,visited函数,层数 
{
	if(visited[n]) return;
	visited[n]=1;
	if(t>T) T=t;
	for(int i:Graph[n])
	{
		dfs(i,visited,t+1);
	}	
	return;
}

3.操作函数process

int T;  //单次遍历的最高层数 
void dfs(int n,vector<int> &visited,int t); 
void process()
{
	vector<int> visited(N+1,0);
	int cnt=1;     //统计连通子图数;
	vector<int> Hroot;
	int MAXT=0; 
	bool flag=0;
	for(int i=1;i<=N;i++)  //将每个结点作文根节点尝试 
	{
		fill(visited.begin(),visited.end(),0);       //不能用resize赋值 
		T=0; 
		dfs(i,visited,0);
		if(T>MAXT)
		{
			Hroot.clear();
			MAXT=T;
			Hroot.push_back(i);
		 } 
		 else if(T==MAXT) Hroot.push_back(i);
		
		for(int j=1;j<=N;j++)//遍历visited,看有无不连通的子图 
		{
			if(!visited[j])
			{
				dfs(j,visited,0);
				cnt++;
				flag=1;
			}
		}
		if(flag) break;
	}
	if(flag) cout<<"Error: "<<cnt<<" components"<<endl;
	else 
	for(int num:Hroot) cout<<num<<endl;
}

4.main函数

int main(){
	input();
	process();
}

解法2:dfs一个节点,得到最大高度的叶节点,再dfs该叶节点之一,得到最大高度的叶节点,两者集合即为最大高度的根节点的集合

C++ (g++) 45 ms 速度快的多

先判断是否连通;
若连通,再对随机一个结点进行dfs,dfs函数里增加保存最深叶节点的操作;
注意初始化即可;

#include<iostream>
#include<vector> 
#include<algorithm>
#include<set>
using namespace std;

int N;
//若不连通,写出有几个子图
vector<vector<int>> Graph; 


void input()
{
	cin>>N;
	Graph.resize(N+1);
	int a,b;
	for(int i=0;i<N-1;i++)
	{
		cin>>a>>b;
		Graph[a].push_back(b);
		Graph[b].push_back(a);
	}	
 } 
  
int T;  //单次遍历的最高层数 
vector<int> result;
void dfs(int n,vector<int> &visited,int t); 

void process()
{
	set<int> res;     //存放并集 
	vector<int> visited(N+1,0);
	int cnt=1;
	bool flag=0;
	
	dfs(1,visited,0);
	for(int j=1;j<=N;j++)//遍历visited,看有无不连通的子图 
		{
			if(!visited[j])
			{
				dfs(j,visited,0);
				cnt++;
				flag=1;
			}
		}
	if(flag) {
		cout<<"Error: "<<cnt<<" components"<<endl;
		return;
	}
	//dfs一个点 
	fill(visited.begin(),visited.end(),0);
	result.clear();
	dfs(1,visited,0);
	for(int i:result) res.insert(i);
	fill(visited.begin(),visited.end(),0);
	dfs(result[0],visited,0);
	for(int i:result) res.insert(i);

	for(int num:res) cout<<num<<endl;

}

void dfs(int n,vector<int> &visited,int t)  //遍历的点,visited函数,层数 
{
	if(visited[n]) return;
	visited[n]=1;
	if(t>T) {
		result.clear();
		result.push_back(n);
		T=t;
	}
	else if (t==T) result.push_back(n);
	
	for(int i:Graph[n])
	{
		dfs(i,visited,t+1);
	}	
	return;
}

int main(){
	input();
	process();
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值