边双联通分量

不多说,操作都是在核心算法的基础上变化,关键的判断 low[v] dfn[u] 之间的关系判段

poj 3177

/*
* this code is made by LinMeiChen
* Problem:
* Type of Problem:
* Thinking:
* Feeling:
*/
#include<iostream>
#include<algorithm>
#include<stdlib.h>
#include<string.h>
#include<stdio.h>
#include<math.h>
#include<string>
#include<vector>
#include<queue>
#include<list>
using namespace std;
typedef long long lld;
typedef unsigned int ud;
#define oo 0x3f3f3f3f
#define maxn 5001
#define maxm 20002
struct Edge
{
	int v, next;
}E[maxn];
int head[maxn], parent[maxn];
int low[maxn], dfn[maxn];
int mark[maxn], bridge[maxn][2];
int belong[maxn], d[maxn];
int con, bg, n, tol;

int find(int x)
{
	if (x == parent[x])
		return x;
	return parent[x] = find(parent[x]);
}

void merge(int x, int y)
{
	int fx = find(x);
	int fy = find(y);
	parent[fx] = fy;
}

void DFS(int u, int fa, int dep)
{
	mark[u] = 1;
	low[u] = dfn[u] = dep;
	for (int i = head[u]; i != -1; i = E[i].next)
	{
		int v = E[i].v;
		if (mark[v] == 0)
		{
			DFS(v, u, dep + 1);
			low[u] = min(low[u], low[v]);
			if (low[v] > dfn[u])
			{
				bridge[bg][0] = u;
				bridge[bg][1] = v;
				bg++;
			}
			else
				merge(u, v);
		}
		else if (v != fa && mark[v] == 1)
			low[u] = min(low[u], dfn[v]);
	}
	mark[u] = 2;
}

void Con_num()
{
	for (int i = 0; i <= n; i++)
		parent[i] = i;
	memset(mark, 0, sizeof mark);
	memset(dfn, 0, sizeof dfn);
	memset(low, 0, sizeof low);
	memset(belong, -1, sizeof belong);
	bg = 0;
	con = 0;
	DFS(1, -1, 1);
	for (int i = 1; i <= n; i++)
	{
		int fa = find(i);
		if (belong[fa] == -1)
			belong[fa] = ++con;
		belong[i] = belong[fa];
	}
}

void add_edge(int u, int v)
{
	E[tol].v = v;
	E[tol].next = head[u];
	head[u] = tol++;
}

int main()
{
	int m, u, v;
	while (scanf("%d%d", &n, &m) != EOF)
	{
		memset(head, -1, sizeof head);
		tol = 0;
		for (int i = 1; i <= m; i++)
		{
			scanf("%d%d", &u, &v);
			add_edge(u, v);
			add_edge(v, u);
		}
		Con_num();
		memset(d, 0, sizeof d);
		for (int i = 0; i < bg; i++)
		{
			u = bridge[i][0];
			v = bridge[i][1];
			d[belong[u]]++;
			d[belong[v]]++;
		}
		int cnt = 0;
		for (int i = 1; i <=con;i++)
		if (d[i] == 1)
			cnt++;
		printf("%d\n", (cnt + 1) / 2);
	}
	return 0;
}

你可能感兴趣的:(边双联通分量)