Tarjan全家桶

有向图强连通分量

030

#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
const int N = 10010;
const int M = 10010;
int n, m, top, num, tot = 0, sum = 0, st[N], last[M], to[M], dfn[N], low[N], vis[N], z[N];
void tarjan(int u)
{
    dfn[u] = low[u] = ++tot;
    z[++top] = u;
    vis[u] = 1;
    for (int i = st[u]; i ; i = last[i])
    {
        if (!dfn[to[i]])
        {
            tarjan(to[i]);
            low[u] = min(low[u], low[to[i]]);
        }
        else
            if (vis[to[i]])
                low[u] = min(low[u], low[to[i]]);
    }
    if (dfn[u] == low[u])
    {
        do
        {
            printf("%d ", z[top]);
            vis[z[top]] = 0;
            top--;
        }while (u != z[top + 1]);
        printf("\n");
    }
}
int main()
{
    scanf("%d%d", &n, &m);
    for (int i = 1; i <= m; i++)
    {
        int u, v;
        scanf("%d%d", &u, &v);
        to[i] = v;
        last[i] = st[u];
        st[u] = i;
    }
    for (int i = 1; i <= n; i++)
        if (!dfn[i])
        {
            memset(z, 0, sizeof z);
            top = 0;
            tarjan(i);
        }
    return 0;
}

割点

两个割点之间即为点双,030

例题:JZOJ 3896

#include<cstdio>
#include<iostream>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
const int N = 50010;
const int M = 200010;
int n, m, tot = 0, cnt = 0, st[N], last[M], to[M], dfn[N], low[N], ans[N], t[N], vis[N];
void add(int u, int v)
{
    to[++cnt] = v;
    last[cnt] = st[u];
    st[u] = cnt;
}
void tarjan(int u, int f)
{
    dfn[u] = low[u] = ++tot;
    int sum = 0;
    for (int i = st[u]; i ; i = last[i])
    {
        if (!dfn[to[i]])
        {
            tarjan(to[i], u);
            low[u] = min(low[u], low[to[i]]);
            if (low[to[i]] >= dfn[u] && !vis[u])
            {
                vis[u] = 1;
                ans[++ans[0]] = u;
            }
        }
        else
            if (to[i] != f) low[u] = min(low[u], dfn[to[i]]);
    }
}
int main()
{
    scanf("%d%d", &n, &m);
    for (int i = 1; i <= m; i++)
    {
        int u, v;
        scanf("%d%d", &u, &v);
        add(u, v);
        add(v, u);
        t[i] = 1;
    }
    tarjan(1, 0);
    sort(ans + 1, ans + ans[0] + 1);
    for (int i = 1; i <= n; i++) printf("%d ", ans[1]);
    return 0;
}                                    

两条桥之间即为边双,030

把割点稍加修改即可

缩点

把联通分量缩成一个点0.0

posted @ 2019-08-11 10:30  featherZHY  阅读(148)  评论(0编辑  收藏  举报