• 18.1.17割点


    原题链接:https://www.luogu.org/problemnew/show/3388

    割点的tarjan算法:
    选定一个节点为根节点,遍历整个图,形成一棵树
    根节点若有两个子树,则其一定是割点。
    对于不是根节点的节点,维护两个数组dfn与low
    dfs[u]表示节点u第几个被访问,low[u]表示节点u最早能回溯到的点
    对于边(u, v),如果low[v]>=dfn[u],此时u就是割点。
    边(u,v),如果v未访问过,dfs之后,更新:low[u]=min(low[u],low[v]);
    访问过,无需dfs,一定有dfn[v]<dfn[u],更新:low[u]=min(low[u], dfn[v])。

    值得一提的是,luogu的割点模板题图可能不连通,而且最后还要按顺序输出,所以,记录好根节点与非根节点,然后最后sort一下。

    #include<cstdio>
    #include<algorithm>
    using namespace std;
    void read(int &y)
    {
        y=0;char x=getchar();
        while(x<'0'||x>'9') x=getchar();
        while(x>='0'&&x<='9')
        {
            y=y*10+x-'0';
            x=getchar();
        }
    }
    int n,m,x,y,cnt,tot,ans;
    struct edge
    {
        int u,v;
    }e[200005];
    int head[100005],va[100005];
    int dfn[100005],low[100005],q[100005];
    int fa[100005],vis[100005],rot[100005];
    void add(int u,int v)
    {
        e[++cnt].u=head[u];
        e[cnt].v=v;
        head[u]=cnt;
    }
    void dfs(int u)
    {
        dfn[u]=low[u]=++tot;
        vis[u]++;
        for(int i=head[u];i;i=e[i].u)
        {
            int v=e[i].v;
            if(vis[v]==0)
            {
                rot[u]++;
                fa[v]=u;
                dfs(v);
                low[u]=min(low[u],low[v]);
                if((vis[u]==2&&rot[u]>1)||(vis[u]==1&&low[v]>=dfn[u]))
                {
                    if(va[u]) continue;
                    va[u]=1;
                    q[++ans]=u;
                }
            }
            else if(v!=fa[u]) low[u]=min(low[u],dfn[v]);
        }
    }
    int main()
    {
    //    freopen("testdata.in","r",stdin);
        read(n);read(m);
        for(int i=1;i<=m;i++)
        {
            read(x);read(y);
            add(x,y);add(y,x);
        }
        for(int i=1;i<=n;i++)
        {
            if(vis[i]==0)
            {
                vis[i]++;
                dfs(i);
            }
        }
        printf("%d
    ",ans);
        sort(q+1,q+ans+1);
        for(int i=1;i<=ans;i++) printf("%d ",q[i]);
        return 0;
    }
  • 相关阅读:
    Educational Codeforces Round 49 (Rated for Div. 2)
    Codeforces Round #506 (Div. 3)
    multiset
    C++中substr函数的用法
    7.30 背包问题
    7.29 dp动态规划
    7.27 图论 存图 前向星 最短路 dijstra算法 SPFA算法
    7.26 搜索进阶(状压搜索,迭代加深搜索)
    7.23 深搜广搜
    7.24 二分搜索
  • 原文地址:https://www.cnblogs.com/zeroform/p/8302561.html
Copyright © 2020-2023  润新知