求树的直径

之前一直没有遇到类似的题,前些天写连通图的时候真是被打了个措手不及,所以下面这个题虽然主要是通过tarjan缩点来求解的,但是前面关于tarjan算法的记录已经完成了,而且求树的直径感觉挺重要的,所以就在这里介绍一下,代码中关于求树的直径的代码很精辟啊,一次深搜完成,是我复制别人的····我自己肯定写不出来这样的代码,难受啊

树的直径通过两次搜索实现(深搜广搜都可以),第一次找出深度最大的节点,第二次以该节点为根再次搜索,再次找到的最大的深度就是树的直径,很简单,实现也不难·····但是要我想的话大概要花一些时间

 N planets are connected by M bidirectional channels that allow instant transportation. It's always possible to travel between any two planets through these channels. 
  If we can isolate some planets from others by breaking only one channel , the channel is called a bridge of the transportation system. 
People don't like to be isolated. So they ask what's the minimal number of bridges they can have if they decide to build a new channel. 
  Note that there could be more than one channel between two planets. 
Input  The input contains multiple cases. 
  Each case starts with two positive integers N and M , indicating the number of planets and the number of channels. 
  (2<=N<=200000, 1<=M<=1000000) 
  Next M lines each contains two positive integers A and B, indicating a channel between planet A and B in the system. Planets are numbered by 1..N. 
  A line with two integers '0' terminates the input.Output  For each case, output the minimal number of bridges after building a new channel in a line.Sample Input
4 4
1 2
1 3
1 4
2 3
0 0 
Sample Output
0

题目大意:有一些星球被一些通道连接着,但是这些通道里面存在一些桥,现在可以新建一个通道,求建一个通道后还剩下的最小桥的个数

题解:对连通分量进行缩点,然后求缩点后的树的直径即可

#include<stdio.h>
#include<string.h>
#include<iostream>
#include<algorithm>

using namespace std;
#define Maxn 200005
#define Maxm 2000005

int dfn[Maxn],low[Maxn];
int cnt[Maxn],du[Maxn];

int jvl[Maxn];
int vis[Maxn];

int head[Maxn];
int u[Maxm];
int v[Maxm];
int _next[Maxm];

int c,num,nu,re;
int sta[Maxn];
int top;

int Max,p;

void into(){
	memset(head,-1,sizeof(head));
	memset(cnt,0,sizeof(cnt));
	memset(dfn,0,sizeof(dfn));
	memset(du,0,sizeof(du));
	memset(vis,0,sizeof(vis));
	c=0;
	num=0;
	nu=0;
	re=0;
	top=0;
	Max=0;p=0;
}

void  add(int s,int t){
	u[c]=s;
	v[c]=t;
	_next[c]=head[s];
	head[s]=c++;
}
void dfs(int k,int fa){
	dfn[k]=low[k]=++num;
	sta[top++]=k;
	int flag=0;
	for(int i=head[k];i!=-1;i=_next[i]){
		int e=v[i];
		if(!dfn[e]){
			dfs(e,k);
			low[k]=min(low[k],low[e]);
		}
		else if(e==fa&&!flag){
			flag=1;
			continue;
		}
		else low[k]=min(low[k],dfn[e]);
	}
	if(dfn[k]==low[k]){
		if(fa!=-1) re++;
		++nu;
		int a;
		do{
			a=sta[--top];
			cnt[a]=nu;
		}while(a!=k);
	}
} 
int dfss(int k,int pre)
{
    int tmp=0;
    for(int i=head[k];i!=-1;i=_next[i])
    {
        int e=v[i];
        if(e==pre||e==k) continue;
        int d=dfss(e,k);
        Max=max(Max,tmp+d);
        tmp=max(tmp,d);
    }
    return tmp+1;
}

void rec(int i){
	u[i]=cnt[u[i]];
	v[i]=cnt[v[i]];
	_next[i]=head[u[i]];
	head[u[i]]=i;
}

int main(){
	int n,m;
	while(scanf("%d%d",&n,&m)){
		if(n==0&&m==0) break;
		into();
		for(int i=0;i<m;i++){
			int s,t;
			scanf("%d%d",&s,&t);
			add(s,t);
			add(t,s);
		}
		for(int i=1;i<=n;i++) if(!dfn[i]) dfs(i,-1);
		memset(head,-1,sizeof(head));
		for(int i=0;i<c;i++) rec(i);
		Max=0;
		dfss(1,-1);
//		printf("%d %d\n",re,Max);
		printf("%d\n",re-Max);
	}
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
第一次实验: 题目1 单链表相关算法的实验验证。 [实验目的] 验证单链表及其上的基本操作。 [实验内容及要] 1、 定义单链表类。 2、 实验验证如下算法的正确性、各种功能及指标: 1)创建单链表; 2)插入操作:分别在当前结点后、表头、表尾插入值为x的结点; 3)删除操作:分别删除表头结点、表尾结点和当前结点的后继结点; 4)存取操作:分别存取当前结点的值和单链表中第k个结点的值; 5)查找操作:查找值为x的元素在单链表中的位置(下标)。 题目2 分别给出堆栈、队列相关算法的实验验证。 [实验目的] 验证堆栈、队列及其上的基本操作。 [实验内容及要](以队列为例) 1、 定义队列类。 2、 实验验证如下算法的正确性、各种功能及指标: 1)创建队列; 2)插入操作:向队尾插入值为x的元素; 3)删除操作:删除队首元素; 4)存取操作:读取队首元素。 第二次实验 题目1 二叉树相关算法的实验验证。 [实验目的] 验证二叉树的链接存储结构及其上的基本操作。 [实验内容及要] 1、 定义链接存储的二叉树类。 2、 实验验证如下算法的正确性、各种功能及指标: 1)创建一棵二叉树,并对其初始化; 2)先根、中根、后根遍历二叉树(递归算法); 3)在二叉树中搜索给定结点的父结点; 4)搜索二叉树中符合数据域条件的结点; 5)从二叉树中删除给定结点及其左右子树。 题目2 树和森林的遍历算法的实验验证。 [实验目的] 验证树和森林的遍历算法。 [实验内容及要] 1、 定义左儿子—右兄弟链接存储的树类和森林类。 2、 实验验证如下算法的正确性、各种功能及指标: 1)创建树和森林; 2)树和森林的先根遍历的递归和迭代算法; 3)树和森林的后根遍历的递归和迭代算法; 4)树和森林的层次遍历算法。 题目3 二叉查找树的验证实验。 [实验目的] 验证二叉查找树及其相关操作。 [实验内容及要] 1、 定义二叉查找树的类。 2、 实验验证如下算法的正确性、各种功能及指标: 1)实现二叉查找树结构; 2) 实现二叉查找树的查找、插入和删除等算法; 第三次实验 题目1 邻接表存储的图相关算法的实验验证。 [实验目的] 验证邻接表存的图及其上的基本操作。 [实验内容及要] 1、 定义邻接表存储的图类。 2、 实验验证如下算法的正确性、各种功能及指标: 1)创建一个邻接表存储的图; 2)返回图中指定边的权值; 3)返回图中某顶点的第一个邻接顶点; 4)返回图中某顶点关于另一个顶点的下一个邻接顶点的序号; 5)插入操作:向图中插入一个顶点,插入一条边; 6)删除操作:从图中删除一个顶点,删除一条边。 题目2 图的遍历算法的实验验证。 [实验目的] 验证图的遍历算法。 [实验内容及要] 1、 定义邻接表存储的图。 2、 实验验证如下算法的正确性、各种功能及指标: 1)创建一个图; 2)图的深度优先遍历的递归算法; 3)图的深度优先遍历的迭代算法; 4)图的广度优先遍历算法。 第四次实验 折半插入排序,堆排序,快速排序 请阅读说明文档

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值