Tarjan缩点(把强连通分量看成一个点)🤪

Posted pupil-xj

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Tarjan缩点(把强连通分量看成一个点)🤪相关的知识,希望对你有一定的参考价值。

// poj 2186 http://poj.org/problem?id=2186

// 翻译后的题意:每个母牛的梦想是成为牛群中最受欢迎的母牛。在N(1 <= N <= 10,000)头牛群中,您最多可以得到M(1 <= M <= 50,000)个有序对(A,B),它们告诉您A牛认为B很受欢迎。由于流行是传递性的,因此如果A认为B流行而B认为C流行,那么A也将认为C 
流行,即使未在输入中由有序对明确指定它也是如此。您的任务是计算被其他所有奶牛所欢迎的奶牛数量。
//将强联通分量缩点,找出出度为0的点,如果只有一个出度为0的点,那么这个点(也可能是经过缩点的点),包含的点的个数就是answer。如果出度为0的点 多于1个,这些出度为0的点之间就没有崇拜关系,肯定输出0了
//上句话从https://blog.csdn.net/u011026968/article/details/10283071复制而来。。。
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;

const int MAXN = 10000+5;
const int MAXM = 50000+5;

struct node 
    int v, next;
 edge[MAXM];
int num;

int head[MAXN];

inline void add_edge(int x, int y) 
    edge[num].v = y;
    edge[num].next = head[x];
    head[x] = num++;


int cnt, t, scc_cnt;
int dfn[MAXN], low[MAXN], sccno[MAXN], stack[MAXN];
int scc_num[MAXN], out[MAXN];

inline void Tarjan(int cur) 
    dfn[cur] = low[cur] = ++cnt;
    stack[t++] = cur;
    for(int i = head[cur]; i != -1; i = edge[i].next) 
        if(!dfn[edge[i].v]) 
            Tarjan(edge[i].v);
            low[cur] = min(low[cur], low[edge[i].v]);
        
        else if(!sccno[edge[i].v]) 
            low[cur] = min(low[cur], dfn[edge[i].v]);
        
    
    if(dfn[cur] == low[cur]) 
        ++scc_cnt;
        int v;
        do 
            v = stack[--t];
            sccno[v] = scc_cnt;
            ++scc_num[scc_cnt];
         while(v != cur);
    


int main() 
    int n, m;
    scanf("%d%d", &n, &m);
    memset(head, -1, sizeof(head));
    int x, y;
    for(int i = 0; i != m; ++i) 
        scanf("%d%d", &x, &y);
        add_edge(x, y);
    
    for(int i = 1; i <= n; ++i) 
        if(!dfn[i]) Tarjan(i);
    
    for(int i = 1; i <= n; ++i) 
        for(int j = head[i]; j != -1; j = edge[j].next) 
            int a = sccno[i], b = sccno[edge[j].v];
            if(a != b) ++out[sccno[i]];
        
    
    int ans = 0;
    int flag;
    for(int i = 1; i <= scc_cnt; ++i) 
        if(!out[i]) 
            ++ans;
            flag = i;
        
    
    if(ans == 1) printf("%d\n", scc_num[flag]);
    else printf("0\n");
    return 0;

 

以上是关于Tarjan缩点(把强连通分量看成一个点)🤪的主要内容,如果未能解决你的问题,请参考以下文章

POJ 2186 Popular Cows tarjan缩点算法

缩点(tarjan求强连通分量)

tarjan强连通分量缩点模板

Tarjan应用:求割点/桥/缩点/强连通分量/双连通分量/LCA(最近公共祖先)

Tarjan应用:求割点/桥/缩点/强连通分量/双连通分量/LCA(最近公共祖先)

P3387 模板缩点(Tarjan求强连通分量)