Luogu P2341 [HAOI2006]受欢迎的牛

P2341 [HAOI2006]受欢迎的牛

题目大意

题面已经说的够明白了

我只是为了多一个标题,走走过场,好看QwQ

思路

题目明确给出的条件足够。既然牛的爱慕关系可以传递,那么自然地就想到了连通分量喽。只要是在同一个连通分量内的牛,它们对整个局面造成的影响是一致的。那么就可以通过Tarjan算法进行缩点。所点后统计每个强连通分量的出度。如果只有一个出度为零的强连通分量(注意是强连通分量),那么这个点就是受欢迎的牛。如果存在两个以上的话,就证明它俩个都没有互相爱慕,那么肯定就不存在受欢迎的牛,所以直接输出0

吐槽一下

woc,Tarjan写错了都能刚出85分来,学到了学到了,我之前交的时候++Index写成了Index++。。。遛了遛了

代码

#include <iostream>
#include <cstring>
#include <cstdio>
#include <stack>

const int maxnode = 1e4+3;
const int maxedge = 5e4+3;

using namespace std;

stack<int> S;
int n, m, first[maxnode], next[maxedge], u[maxedge], v[maxedge], num[maxnode];
int low[maxnode], dfn[maxnode], Index, cnt, in[maxnode], Indgr[maxnode];
bool vis[maxnode];

inline int readInt() {
    int x = 0, f = 1;
    char c = getchar();
    while (c < '0' || c > '9') {
        if(c == '-') f = -1;
        c = getchar();
    }
    while (c <= '9' && c >= '0') {
        x = x*10 + c-'0';
        c = getchar();
    }
    return x * f;
}

inline void addedge(int f, int i) {
    next[i] = first[f];
    first[f] = i;
}

inline void Tarjan(int x) {
    low[x] = dfn[x] = ++Index;
    vis[x] = 1;
    S.push(x);
    int k = first[x];
    while (k != -1) {
        if(!dfn[v[k]]) {
            Tarjan(v[k]);
            low[x] = min(low[x], low[v[k]]);
        }
        else if(vis[v[k]]) {
            low[x] = min(low[x], dfn[v[k]]);
        }
        k = next[k];
    }
    if(dfn[x] == low[x]) {
        cnt++;
        while (!S.empty()) {
            int temp = S.top();
            S.pop();
            vis[temp] = 0;
            in[temp] = cnt;
            num[cnt]++;
            if(temp == x) break;
        }
    }
}

int main() {
    n = readInt(), m = readInt();
    memset(first, -1, sizeof(first));
    for(int i=1; i<=m; i++) {
        u[i] = readInt(); v[i] = readInt();
        addedge(u[i], i);
    }
    for(int i=1; i<=n; i++) {
        if(!dfn[i]) Tarjan(i);
    }
    for(int i=1; i<=n; i++) {
        int k = first[i];
        while (k != -1) {
            if(in[v[k]] != in[u[k]])
                Indgr[in[u[k]]]++;
            k = next[k];
        }
    }
    int mark = 0;
    for(int i=1; i<=cnt; i++) {
        if(Indgr[i] == 0) {
            if(mark) {
                printf("0
");
                return 0;
            }
            mark = i;
        }
    }
    printf("%d", num[mark]);
}
原文地址:https://www.cnblogs.com/bljfy/p/9326200.html