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 (双联通,缩点)