双连通分量

本文介绍了如何构建边双连通分量,包括洛谷P2860 [USACO06JAN]Redundant Paths G题目中的边双连通分量概念和公式,并探讨了UVA12167 Proving Equivalences问题,涉及将有向图变为强连通图的最小边数策略。
摘要由CSDN通过智能技术生成

洛谷P2860 [USACO06JAN]Redundant Paths G

边双连通分量

定义:没有割边(删除任意一条边对图得连通性没有影响)
扩展:图上任何两个点都有两种及以上不同路径互相到达
板子题
题意:缩点后的图是一棵树,在树中最少增加几条边,可以使树变为边双连通分量
公式:增加边数 = (树中度为1的节点数 + 1)/ 2

#include<bits/stdc++.h> 
using namespace std;
const long long inf=0x3f3f3f3f;
const long long maxn=1e6;
int head[maxn],a[maxn],b[maxn],w[maxn],to[maxn],k1,n,m,next[maxn],in[maxn],low[maxn],dfn[maxn],id[maxn],nid,cnt,sum,f[maxn],ct;
bool vis[maxn];
void add (int a,int  b){
	to[++k1]=b;
	next[k1]=head[a];
	head[a]=k1;
}
stack<int>p;
void tarjan(int x,int fa){
	low[x]=dfn[x]=++cnt;
	p.push(x);
	vis[x]=1;
	for(int i=head[x];i;i=next[i]){
		int y=to[i];
		if(fa==f[i])continue;
		if(!dfn[y]){
			tarjan(y,f[i]);
			low[x]=min(low[x],low[y]);
		}
		else if(vis[y])low[x]=min(low[x],dfn[y]);
	}
	if(low[x]==dfn[x]){
		nid++;
		int now=0;
		do{
			now=p.top();
			p.pop();
			id[now]=nid;
			vis[now]=0;
		}while(x!=now);
	}
}

int main(){
	scanf("%d%d",&n,&m);
	for(int i=1;i<=m;i++){
		scanf("%d%d",&a[i],&b[i]);
	    add(a[i],b[i]),f[k1]=++ct;
		add(b[i],a[i]),f[k1]=ct;
    }
    for(int i=1;i<=n;i++)
	    if(!dfn[i])
		tarjan(i,0);
	for(int i=1;i<=m;i++){
		int sa=id[a[i]],sb=id[b[i]];
		if(sa!=sb)in[sa]++,in[sb]++;
	}
	for(int i=1;i<=nid;i++){
		if(in[i]==1)sum++;
	} 
	printf("%d\n",(sum+1)/2);
    return 0;
}
洛谷UVA12167 Proving Equivalences

题意:

给出 nn 个点 mm 条边的有向图,问最少再加上多少条边才能使这个图是强连通的

思路:

缩点后,若图已经连通,则直接输出 0 。否则,答案 = min ( 入度 == 0 ,出度 == 0)

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值