POJ 3177 Redundant Paths(边双连通分量+tarjan)

本文介绍了一种求解边双连通图最小优化问题的方法。通过Tarjan算法进行缩点处理,将双连通块视为单一节点,形成树状结构。在此基础上,通过连接叶子节点来构建边双连通图,所需添加的边数等于(叶子节点数量+1)/2。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目链接:http://poj.org/problem?id=3177

题目大意:给你一个连通图,问你最少添加几条边能组成一个边双连通图,有重边

思路:我们将所有的双连通块看成一个点,因为他们是连通的且不成一个环,利用tarjan缩点后就可以看做一棵树

这样的树至少需要加多少条边就能构成一个双连通图呢,我们只需要将叶子节点连起来即可,因为是无向图,所以

度为1的就是叶节点而不是度为0,这样我们要添加的边数就为(叶子结点总数+1)/2,加1是因为叶子结点可能为

奇数的,而且要注意tarjan在无向图与有向图的不同写法

上代码:

#include<iostream>
#include<cmath>
#include<cstring>
#include<string>
#include<cstdio>
#include<queue>
#include<stack>
#include<vector>
#include<algorithm>
using namespace std;
#define inf 0x3f3f3f3f
#define mod 1e9+7
#define ll long long
#define maxn 5000+10
vector<int>G[maxn];
bool visit[maxn],falg[maxn][maxn];
int dfn[maxn], low[maxn], cnt[maxn];
int n, m,index;
void tarjan(int u, int father)
{
	dfn[u] = low[u] = ++index;
	visit[u] = true;
	for (int i = 0; i < G[u].size(); i++)
	{
		int k = G[u][i];
		if (!visit[k])
		{
			tarjan(k, u);
			low[u] = min(low[u], low[k]);
		}
		else if (visit[k]&&(k != father))//自己不能回到父节点,必须透过其他路径回去
			low[u] = min(low[u], dfn[k]);//为什么是dfn[v],因为如果low[v]<dfn[v]就说明
		//v已经是别的双连通分支的点了,不能再去动用他了
	}
}
void solve()
{
	memset(visit, false, sizeof(visit));
	memset(low, 0, sizeof(low));
	memset(dfn, 0, sizeof(dfn));
	memset(cnt, 0, sizeof(cnt));
	index = 0;
	tarjan(1, 1);//如果是不连通的图,加个for(1 to n)
	for (int i = 1; i <= n; i++)
	{
		for (int j = 0; j < G[i].size(); j++)
		{
			if (low[G[i][j]] != low[i])
				cnt[low[i]]++;//计算缩点后每个点的度
		}
	}
	int sum = 0;
	for (int i = 1; i <= n; i++)
		if (cnt[i] == 1)//度为1为叶节点
			sum++;
	printf("%d\n", (sum + 1) / 2);//为什么是(sum+1)/2呢,画图好理解
	for (int i = 1; i <= n; i++)
		G[i].clear();
}
int main()
{
	//freopen("Text.txt", "r", stdin);
	int u, v;
	while (scanf("%d%d", &n, &m) != EOF)
	{
		memset(falg, false, sizeof(falg));
		while (m--)
		{
			scanf("%d%d", &u, &v);
			if(!falg[u][v])//去重边
			{ 
				G[u].push_back(v);
				G[v].push_back(u);
				falg[u][v] = true;
				falg[v][u] = true;
			}
		}
		solve();
	}
	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值