P2860[USACO06JAN]Redundant Paths G(边双连通分量&无向图缩点)

Posted Harris-H

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了P2860[USACO06JAN]Redundant Paths G(边双连通分量&无向图缩点)相关的知识,希望对你有一定的参考价值。

P2860[USACO06JAN]Redundant Paths G(边双连通分量&无向图缩点)

题意:给定无向连通图,求最小加边的数量使得图为边双连通分量图。

思路:

边双连通分量的定义:对于图中的任意两点都存在至少两条不重合的路径,使得能两点连通。

桥的定义:两端是边双连通分量的边。

本题思路即为将所有边双连通分量缩点后与桥组成的一棵树,使得该树任意两点的度数至少为2的最小加边数,因此缩点后,我们进行统计每个点的度数。

答案即为: = ⌈ c n t 2 ⌉ = c n t + 1 2 =\\lceil\\dfrac{cnt}{2}\\rceil=\\dfrac{cnt+1}{2} =2cnt=2cnt+1

即让度数为1的点两两配对,若有多余的一个点,则该点也要进行配对。

另外需要注意的是:边是无向边,统计度数时,如果用链式前向星的话,边会算两次。相当于统计度数为2的点。

code

// Problem: P2860 [USACO06JAN]Redundant Paths G
// Contest: Luogu
// URL: https://www.luogu.com.cn/problem/P2860
// Memory Limit: 125 MB
// Time Limit: 1000 ms
// Date: 2021-07-05 14:49:28
// --------by Herio--------

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull; 
const int N=5e3+5,M=1e4+5,inf=0x3f3f3f3f,mod=1e9+7;
#define mst(a,b) memset(a,b,sizeof a)
#define PII pair<int,int>
#define fi first
#define se second
#define pb emplace_back
#define SZ(a) (int)a.size()
#define ios ios::sync_with_stdio(false),cin.tie(0) 
void Print(int *a,int n){
	for(int i=1;i<n;i++)
		printf("%d ",a[i]);
	printf("%d\\n",a[n]); 
}
int n,m;
int h[N],cnt=1,vis[N],bl[N],tot,dfn[N],low[N];
struct edge{
	int to,nt,f;
}e[M<<1];
void add(int u,int v){
	e[++cnt]={v,h[u],0},h[u]=cnt;
	e[++cnt]={u,h[v],0},h[v]=cnt;
}
int id;
stack<int>s;
void dfs(int u){
	dfn[u]=low[u]=++id;
	s.push(u);vis[u]=1;
	for(int i=h[u];i;i=e[i].nt)
		if(!e[i].f){
			e[i].f=e[i^1].f=1;
			int v=e[i].to;
			if(!dfn[v]) dfs(v),low[u]=min(low[u],low[v]);
			else if(vis[v]) low[u]=min(low[u],dfn[v]);
		}
	if(dfn[u]==low[u]){
		bl[u]=++tot;
		vis[u]=0;
		while(s.top()!=u){
			bl[s.top()]=tot;
			vis[s.top()]=0;
			s.pop();
		}
		s.pop();
	}
}
int d[N],U[N],V[N];
int main(){
	scanf("%d%d",&n,&m);
	for(int i=1;i<=m;i++){
		scanf("%d%d",&U[i],&V[i]);
		add(U[i],V[i]);
	}
	for(int i=1;i<=n;i++) if(!dfn[i]) dfs(i);
	for(int i=1;i<=m;i++)
			if(bl[U[i]]!=bl[V[i]]) d[bl[U[i]]]++,d[bl[V[i]]]++;
	int ans=0;
	for(int i=1;i<=tot;i++) if(d[i]==1) ans++;
		for(int u=1;u<=n;u ++)
		for(int i=h[u];i;i=e[i].nt){
			int v=e[i].to;
			if(bl[u]!=bl[v]) d[bl[u]]++,d[bl[v]]++;
		}
	/*
		for(int u=1;u<=n;u ++)
		for(int i=h[u];i;i=e[i].nt){
			int v=e[i].to;
			if(bl[u]!=bl[v]) d[bl[u]]++,d[bl[v]]++;
		}
	int ans=0;
	for(int i=1;i<=tot;i++) if(d[i]==2) ans++;
	*/
	printf("%d\\n",ans+1>>1);
	return 0;
}

以上是关于P2860[USACO06JAN]Redundant Paths G(边双连通分量&无向图缩点)的主要内容,如果未能解决你的问题,请参考以下文章

洛谷P2860 [USACO06JAN]冗余路径Redundant Paths(tarjan求双联通分量)

P2860[USACO06JAN]Redundant Paths G(边双连通分量&无向图缩点)

LUOGU P2860 [USACO06JAN]冗余路径Redundant Paths (双联通,缩点)

luogu题解 P2860[USACO冗余路径Redundant Paths] 缩点+桥

[USACO06JAN]牛的舞会The Cow Prom

P2863 [USACO06JAN]牛的舞会The Cow Prom