Luogu P2863 [USACO06JAN]The Cow Prom S

思路

这个题就是纯正的Tarjan模板题,关于难以理解的、玄学的low数组,建议感性理解。网上的解释千姿百态,啥样的都有,有的对有的错,看多了反而会晕。所以建议Tarjan模板基本的几个部分多打几遍,

熟练了就好(不建议强求理解)。

Code

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#define MAXN 20010
#define MAXM 50010
int n, m, idx;
int head[MAXM], cnt;
int dfn[MAXN], low[MAXN];
int stk[MAXN], top, size[MAXN];
int flag[MAXN], bel[MAXN], scc;
struct node{
    int nxt, to;
} edge[MAXM];
inline int read(void){
    int f = 1, x = 0;char ch;
    do{ch = getchar();if(ch=='-')f = -1;} while (ch < '0' || ch > '9');
    do{ x = x * 10 + ch - '0';ch = getchar();} while (ch >= '0' && ch <= '9');
    return f * x;
}
inline int _min(int x,int y){
    return x < y ? x : y;
}
inline void add_edge(int x,int y){
    ++cnt;
    edge[cnt].nxt = head[x];
    edge[cnt].to = y;
    head[x] = cnt;
    return;
}
void tarjan(int k){
    dfn[k] = low[k] = ++idx;
    stk[++top] = k;
    flag[k] = 1;
    for (int i = head[k]; i; i = edge[i].nxt){
        int v = edge[i].to;
        if(!dfn[v])
            tarjan(v), low[k] = _min(low[k], low[v]);
        else if(flag[v]) low[k] = _min(low[k], dfn[v]);//这几个min代码量也不大,建议背诵(大部分Tarjan题都不会对这两个min做出变动)
    }
    if(dfn[k]==low[k]){
        int now = -1;
        ++scc;
        while(now!=k){
            now = stk[top], --top;
            flag[now] = 0;
            ++size[scc];
            bel[now] = scc;
        }//每次找到返祖边(环)后统计答案
    }
}
int main(){
    n = read(), m = read();
    for (int i = 1; i <= m; ++i){
        int u = read(), v = read();
        add_edge(u, v);//连有向边
    }
    for (int i = 1; i <= n; ++i)
        if(!dfn[i]) tarjan(i);//注意原图可能不连通
    // for (int i = 1; i <= n; ++i){
    //     printf("dfn[%d]=%d,low[%d]=%d\n", i, dfn[i], i, low[i]);
    // }
    int ans = 0;
    for (int i = 1; i <= scc; ++i)
        if(size[i]>1) ++ans;//统计大小大于1的强连通分量个数
    printf("%d\n", ans);
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/ShadowFlowhyc/p/13380898.html
今日推荐