【刷题】【割点和桥】冗余路径

对于同一对草场之间,可能已经有两条不同的道路

题真的应该看仔细啊

//一个问题,如何变成 边双联通分量 
//leaf+1>>1 
#include<cstdio>
#include<cstdlib>
#include<stack>
using namespace std;
inline int read()
{
    int x=0;char c=getchar();
    while(c<'0' || c>'9') c=getchar();
    while(c>='0'&&c<='9') x=(x<<3)+(x<<1)+c-'0',c=getchar();
    return x;
}
int n,m;
const int N=5003,M=10003;
int col[N],sum;

int tot=1,head[N]; 
int ev[M<<1],enx[M<<1];
void add(int u,int v)
{    ev[++tot]=v,enx[tot]=head[u],head[u]=tot;
    ev[++tot]=u,enx[tot]=head[v],head[v]=tot;    }

int dfn[N],low[N],cnt;
stack <int> s;
void tarjan(int rt,int pre)//强连通缩点
{
    dfn[rt]=low[rt]=++cnt;
    s.push(rt);
    
    for(int i=head[rt];i;i=enx[i])
        if((pre^1) != i )//对于同一对草场之间,可能已经有两条不同的道路
        {
            if(!dfn[ev[i]])
                tarjan(ev[i],i);    
            low[rt]=min(low[rt],low[ev[i]]);
        }
    if(dfn[rt]==low[rt])
    {
        col[rt]=++sum;
        while(s.top() !=rt)
            col[s.top() ]=sum,s.pop() ;
        s.pop() ;
    }    
}

int in[N];
int main()
{
    n=read(),m=read();
    for(int i=1;i<=m;i++)
        add(read(),read());
    for(int i=1;i<=n;i++)
        if(!dfn[i])
            tarjan(i,0);
    
    int ans=0;
    for(int i=2;i<tot;i+=2)
        if(col[ev[i]]!=col[ev[i|1]] )
            in[col[ev[i]]]++,in[col[ev[i|1]]]++;
    for(int i=1;i<=sum;i++)
        if(in[i]==1) ans++; 
    printf("%d\n",ans+1>>1);
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/xwww666666/p/11755478.html