POJ3352Road construction(边双联通分量)

本文探讨了一个图论问题,即如何通过在无向连通图中添加最少数量的边,使得任意两点间存在两条无公共边的路径。文章提供了算法实现,包括缩点、统计度数为1的点数量,并最终得出解决方案。

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

传送门

 

大意:

 

一张无向连通图 问你 最少添加多少条边,使得任意两点之间有两条无公共边的路(可以有公共点)

 

有这样一个结论:

 

答案是缩点后所有度数为1的点的数量(num+1)/2

 

缩点后相当于是一颗树

 

考虑对于所有叶子节点

 

将其两两连边

 

如果还剩一个则还需要连一条边

 

所有我们只需要缩点后统计度数就是了

 

注意要判重边

 

#include<algorithm>
#include<cmath>
#include<cstring>
#include<iostream>
#include<cstdlib>
#include<cstdio>
#include<stack>
#include<map>
using namespace std;
#define ll long long
inline int read(){
	char ch=getchar();
	int res=0;
	while(!isdigit(ch))ch=getchar();
	while(isdigit(ch))res=(res<<3)+(res<<1)+(ch^48),ch=getchar();
	return res;
}
int n,m,adj[50005],nxt[100005],vis[50005],to[100005],in[50005],dfn[50005],low[50005],bel[50005],belnum,ans,cnt=1,tot;
stack<int> stk;
inline void addedge(int u,int v){
	nxt[++cnt]=adj[u],adj[u]=cnt,to[cnt]=v;
	nxt[++cnt]=adj[v],adj[v]=cnt,to[cnt]=u;
}
inline void tarjan(int u,int pre){
	dfn[u]=low[u]=++tot;
	stk.push(u);
	for(int e=adj[u];e;e=nxt[e]){
		if((e^1)==pre)continue;//判重边的骚操作,但注意要把建边的cnt设为1或-1
		int v=to[e];
		if(!dfn[v]){
			tarjan(v,e);
			low[u]=min(low[u],low[v]);
		}
		else low[u]=min(low[u],dfn[v]);
	}
	if(low[u]==dfn[u]){
		belnum++;
		int tmp;
		do{
			tmp=stk.top();
			bel[tmp]=belnum;
			stk.pop();
		}while(tmp!=u);
	}
}
int main(){
	n=read(),m=read();
	for(int i=1;i<=m;i++){
		int u=read(),v=read();
			addedge(u,v);
	}
	tarjan(1,0);
	for(int u=1;u<=n;u++){
		for(int e=adj[u];e;e=nxt[e]){
			int v=to[e];
			if(bel[u]!=bel[v]){
				in[bel[u]]++;
			}
		}
	}
	for(int i=1;i<=belnum;i++){
		if(in[i]==1)ans++;
	}
	cout<<(ans+1)/2;
}

 

转载于:https://www.cnblogs.com/stargazer-cyk/p/10366439.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值