牛客小白月赛12(i)华华和月月逛公园(tarjin)

题目:https://ac.nowcoder.com/acm/contest/392/I

首先先了解一下什么是割边割点!!!

割边:在无向图中,如果删除图中的一条边,图的连通分量增加,那就称该边为割边。(割边可以有多个)

割点:同理,在无向图中如果删除图中的一个顶点及顶点的邻边,图的连通分量增加,则称该点为割点。(割点也可以有多个)

方法:tarjin算法找割边的数量ans(割边是一定要走的边),所以不一定要走的边的数量为m-ans。

        这里,解释一下为什么要找割边,(画个图会很清楚的看出来)就拿题目的样例(如下)来说,{1,2,3,4,5}构成了个连通分量,如果我删除1to2或者2to3这个边,那么连通分量会变成{1},{2,3,4,5}或者{1,2},{3,4,5},与此同时,会导致所有的景点无法完全经过,因为割边是连接两端连通分量的唯一边!!!

5 5
1 2
2 3
3 4
4 5
3 5

#include<iostream>
#include<list>

using namespace std;

const int maxn=100005;

int low[maxn],dfn[maxn],ans,p; //dfn数组记录第一次经过这个顶点(下标)的时间戳,low记录的是可以经过这个顶点的最小时间戳(会在递归后进行更新得到最小的时间戳),ans记录割边的数量,p为当前时间戳
list<int> g[maxn];
list<int> sta;                  //没啥用。

void dfs(int u,int fa)      //此处的dfs即为tarjin算法的遍历方法
{
	low[u]=dfn[u]=++p;      //初始化两个时间戳数组
//    cout<<u<<endl;

	for(list<int >::iterator i=g[u].begin();i!=g[u].end();i++)
	{
	    int v=*i;
	    if(v==fa) continue;
		if(!low[v])
		{
			dfs(v,u);
			low[u]=min(low[v],low[u]);  //递归后更新当前点的最小时间戳,将dfs尽头的顶点的low传递下来,表示当前顶点属于某个连通分量

			if(low[v]>dfn[u]) ans++;   //记录割边的数量,如果' > '改成' >= '则ans是割点数量+1
		}
		else if(dfn[v]) low[u]=min(low[u],low[v]);  //遍历到顶点v,如果v已经遍历过的,则取v的low时间戳给u
	}
//	cout<<endl;
}

int main()
{
	int n,m;

	cin>>n>>m;

	for(int i=0;i<m;i++)
	{
		int u,v;

		cin>>u>>v;

		g[u].push_back(v);
		g[v].push_back(u);
	}

	dfs(1,0);

//   for(int i=1;i<=n;i++) cout<<low[i]<<' '<<dfn[i]<<endl;
    cout<<m-ans<<endl;

	return 0;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值