无向图强联通分量-洛谷 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);
}
posted @ 2017-02-24 18:45  largecube233  阅读(108)  评论(0编辑  收藏  举报