zoukankan      html  css  js  c++  java
  • poj-3177(无向图缩点)

    题意:给你n个点,m条边的无向联通图,问你最少增加几条边,使得这个图每对点至少有两条路径

    解题思路:考虑每个环内的点必定有>=2条路径,所以先把这个无向图中的环去掉,用并查集缩环,然后剩下的图一定是个割边树,只需要把度为1的结点数/2就是答案了(把这棵树变成环);

    代码:

    #include<iostream>
    #include<cstring>
    #include<cstdio>
    #include<algorithm>
    using namespace std;
    const int maxn=100500;
    struct Edge
    {
        int next;int to;int id;
    }edge[maxn];
    int head[maxn],cnt,low[maxn],visit[maxn],dfn[maxn],step,ans,n,m;
    int f[maxn],x[maxn],y[maxn];
    int deg[maxn];
    void init()
    {
        memset(deg,0,sizeof(deg));
        memset(head,-1,sizeof(head));
        memset(low,0,sizeof(low));
        memset(dfn,0,sizeof(dfn));
        for(int i=1;i<=n;i++)
            f[i]=i;
        cnt=step=0;
    }
    int findf(int u)
    {
        if(f[u]==u)
            return u;
        else
        {
            f[u]=findf(f[u]);
            return f[u];
        }
    }
    void join(int u,int v)
    {
        int t1=findf(u);int t2=findf(v);
        if(t2!=t1)
        {
            f[t2]=t1;
        }
    }
    void add(int u,int v,int id)
    {
        edge[cnt].next=head[u];edge[cnt].to=v;edge[cnt].id=id;head[u]=cnt++;
        edge[cnt].next=head[v];edge[cnt].to=u;edge[cnt].id=id;head[v]=cnt++;
    }
    void tarjan(int u,int fa)
    {
        dfn[u]=low[u]=++step;
        for(int i=head[u];i!=-1;i=edge[i].next)
        {
            int v=edge[i].to;
            int id=edge[i].id;
            if(fa==id)
                continue;
            if(!dfn[v])
            {
                tarjan(v,id);
                low[u]=min(low[u],low[v]);
                if(dfn[u]<low[v])
                {
                    ans++;
                }
                else
                {
                    join(u,v);
                }
            }
            else
            {
                low[u]=min(low[u],dfn[v]);
            }
        }
    }
    int main()
    {
    
        scanf("%d%d",&n,&m);init();
        for(int i=1;i<=m;i++)
        {
            scanf("%d%d",&x[i],&y[i]);
            add(x[i],y[i],i);
        }
        tarjan(1,0);
        for(int i=1;i<=m;i++)
        {
            if(findf(x[i])==findf(y[i]))
                continue;
            else
            {
                deg[findf(x[i])]++;deg[findf(y[i])]++;
            }
        }
        int cot=0;
        for(int i=1;i<=n;i++)
        {
            if(deg[i]==1)
                cot++;
        }
        printf("%d
    ",(cot+1)/2);
    }
  • 相关阅读:
    C#中递归算法的总结
    C# 创建错误日志
    获取指定路径下所有PDF文件的总页数
    C# 将文件转为字符串和将字符串转为文件的方法
    如何获得应用程序的物理路径
    C#中获得文件夹下所有文件的两种方法
    C#中加密与解密
    MacOS系统使用Homebrew官方地址报错
    privoxy代理服务器配置
    Nginx 反向代理 502 permission denied 解决
  • 原文地址:https://www.cnblogs.com/huangdao/p/10631785.html
Copyright © 2011-2022 走看看