无向图强联通分量-洛谷 P2860 [USACO06JAN]冗余路径Redundant Paths
https://www.luogu.org/problem/show?pid=2860
这个就是无向图的强联通;
有向图的两点再一个分量里,是x可以到y,y也可到x;
但无向图本来就是双向的,所以我们再dfs的时候不能直接访问其亲爹;
这样的话,x,y有两条及以上的无共边的路径(就是环),那他们在一个强连通分量里面;
这里{1}{2345}是两个强连通分量;
在这题目里,就是让我们求要添几条变,可以让原图变成一个强连通分量;
那我们先把原图搞一下缩点,无向图缩点后必然会变成一颗树;
树上所有点都互相联通但是无环;
树上必然会产生只有一个儿子的节点;
我们把这些点找出来;
然后以他们为叶子节点弄一个树;
很显然我们只有把这些叶子节点互相连边,就可以形成很多环;
设有N个叶子节点,那我们最少要连(n+1)/2个;
及答案。
为什么?,画画图吧,可以用树的基本特征口胡的;
#include<cstdio>//cfb
#include<cstdlib>
#include<iostream>
#include<algorithm>
#include<cmath>
#include<cstring>
#include<map>
using namespace std;
struct cs{
int to,next;
}a[20001];
int head[5001],low[5001],tt[5001],q[5001],lin[5001],cc[10001][2],sum[5001];
bool in[5001],f[5001][5001];//f用来判重
int ll,n,m,x,y,z,t,nn,CC,aa,bb,ans,mm;
void init(int x,int y){
a[++ll].to=y;
a[ll].next=head[x];
head[x]=ll;
}
void dfs(int x,int y){
tt[x]=++t; low[x]=t; q[++q[0]]=x; in[x]=1;
for(int k=head[x];k;k=a[k].next)
if(a[k].to!=y){//不回溯亲爹
if(!tt[a[k].to])dfs(a[k].to,x);
if(in[a[k].to])low[x]=min(low[x],low[a[k].to]);
}
if(low[x]==tt[x]){
nn++;
while(1){
in[q[q[0]]]=0;
lin[q[q[0]]]=nn;
q[0]--;
if(q[q[0]+1]==x)break;
}
}
}
int main()
{
scanf("%d%d",&n,&m);
for(int i=1;i<=m;i++){
scanf("%d%d",&x,&y);
if(!f[x][y])mm++;else continue;
f[x][y]=f[y][x]=1;
init(x,y); init(y,x);
cc[mm][0]=x;cc[mm][1]=y;
}
for(int i=1;i<=n;i++)if(!tt[i])dfs(i,-1);
for(int i=1;i<=mm;i++){
x=cc[i][0];y=cc[i][1];
if(lin[x]==lin[y])continue;
sum[lin[x]]++; sum[lin[y]]++;//统计每个点有几个儿子
}
for(int i=1;i<=nn;i++)if(sum[i]==1)ans++;
printf("%d",(ans+1)/2);
}