luogu2860 无向图边双连通分量

和有向图区别就是当同一条无向边的两条有向边的其中一条走过时,把另一条同时赋值为走过,这样tarjan时就能得到正确的low[x];

#include <bits/stdc++.h>
using namespace std;
const int N = 5e3 + 5, M = 1e4 + 5;
int n, m, vis[M << 1], du[N], ans;
int cnt = 1, head[N], u[M], v[M];
int now, top, col, dfn[N], low[N], sta[N], color[N];
struct edge { int next, to; }e[M << 1];

inline void add(int u, int v)
{
	cnt++;
	e[cnt].next = head[u];
	e[cnt].to = v;
	head[u] = cnt;
	cnt++;
	e[cnt].next = head[v];
	e[cnt].to = u;
	head[v] = cnt;
}

inline void tarjan(int u)
{
	dfn[u] = low[u] = ++now;
	sta[++top] = u;
	for (register int i = head[u]; i; i = e[i].next)
		if (!vis[i])
		{
			vis[i] = vis[i ^ 1] = 1;
			if (!dfn[e[i].to])
			{
				tarjan(e[i].to);
				low[u] = min(low[u], low[e[i].to]);
			}
			else low[u] = min(low[u], dfn[e[i].to]);
		}
	if (low[u] == dfn[u])
	{
		color[u] = ++col;
		while (sta[top] != u) color[sta[top]] = col, top--;
		top--;
	}
}

int main() {
	memset(head, 0, sizeof(head));
	memset(dfn, 0, sizeof(head));
	//下面过程如果不懂,看前面的几篇题解吧
	scanf("%d%d", &n, &m);
	for (register int i = 1; i <= m; ++i) scanf("%d%d", &u[i], &v[i]), add(u[i], v[i]);
	for (register int i = 1; i <= n; ++i) if (!dfn[i]) tarjan(i);
	for (register int i = 1; i <= m; ++i) if (color[u[i]] != color[v[i]]) du[color[u[i]]]++, du[color[v[i]]]++;
	for (register int i = 1; i <= col; ++i) if (du[i] == 1) ans++;
	printf("%d\n", ans + 1 >> 1);
	return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值