冗余路径 Redundant Paths e-DCC缩点

冗余路径 Redundant Paths

题目传送

sol:

如果两点间存在至少两条不重复的路径,这说明他们两点在同一个边双连通分量(不存在割边)。

那么可以进行e-DCC的缩点,得到一棵树。

对于这棵树广泛意义上的叶子节点(度数为1)而言,都还至少需要一条边连向他。

那么可以贪心的一次连两个叶子节点,答案显然就是\(cnt+1>>1\)

#include<bits/stdc++.h>
#define IL inline
#define RG register
#define DB double
#define LL long long
using namespace std;

const int N=5005;
const int M=1e4+5;

int n,m,tot,cnt,leaf,Time,head[N],bel[N],vis[N],low[N],dfn[N],bri[M<<1];

struct edge{int x,y;}s[M];
struct EDGE{int next,to;}e[M<<1];

IL int gi() {
    RG int x=0,p=1; RG char ch=getchar();
    while(ch<'0'||ch>'9') {if(ch=='-') p=-1;ch=getchar();}
    while(ch>='0'&&ch<='9') x=x*10+(ch^48),ch=getchar();
    return x*p;
}

IL void New() {
    tot=0;
    memset(&e,0,sizeof(e));
    memset(head,0,sizeof(head));
}

IL void make(int a,int b) {
    e[++tot]=(EDGE){head[a],b},head[a]=tot;
    e[++tot]=(EDGE){head[b],a},head[b]=tot;
}

void Tarjan(int x,int fx) {
    RG int i,y;
    dfn[x]=low[x]=++Time;
    for(i=head[x];i;i=e[i].next) {
        if(!dfn[y=e[i].to]) {
            Tarjan(y,x),low[x]=min(low[x],low[y]);
            if(low[y]>dfn[x]) bri[i]=bri[i^1]=1; 
        }
        else if(y!=fx) low[x]=min(low[x],dfn[y]);
    }   
}

void dfs(int x) {
    RG int i,y;
    bel[x]=cnt,vis[x]=1;
    for(i=head[x];i;i=e[i].next)
        if(!vis[y=e[i].to]&&!bri[i]) dfs(y);
}

void dfs2(int x,int fx) {
    RG int i,y,fl=0;
    for(i=head[x];i;i=e[i].next)
        if((y=e[i].to)!=fx) fl=1,dfs2(y,x);
    if(!fl) ++leaf;
}

int main()
{
    RG int i,b=0;
    n=gi(),m=gi(),tot=1;
    for(i=1;i<=m;++i)
        s[i].x=gi(),s[i].y=gi(),make(s[i].x,s[i].y);
    for(i=1,Tarjan(1,0);i<=n;++i)
        if(!vis[i]) ++cnt,dfs(i);
    if(cnt==1) return puts("0"),0;
    for(i=1,New();i<=m;++i)
        if(bel[s[i].x]!=bel[s[i].y]) make(bel[s[i].x],bel[s[i].y]);
    dfs2(1,0);
    for(i=head[1];i;i=e[i].next) ++b;
    if(b==1) ++leaf;
    printf("%d\n",leaf+1>>1);
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/Bhllx/p/11258322.html
今日推荐