poj-2186-Popular Cows (tarjan算法)

39 篇文章 0 订阅

题意:有n只牛,牛之间存在一些关系,比如a认为b很受欢迎,b认为c很受欢迎,这样呢,a也会认为c很受欢迎,问根据给出的关系,有多少头牛被其他所有的牛都认为是受欢迎的?

思路:求强连通分量缩点后反向建图
然后判断图中是否有且仅有一个点的入度为 0,是的话就输出这个店包含的牛的个数,否则就输出 0

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <stack>
#include <string>
#include <algorithm>
#define ll long long
using namespace std;
const int inf=0x3ffffff;
const int MAXN = 10003;
const double eps = 1e-6;

int next[MAXN<<3], to[MAXN<<3], head[MAXN<<3], tot;
int scc, dep; 
int dfn[MAXN], low[MAXN], id[MAXN];
bool mark[MAXN];
stack<int> sta;

void tarjan(int v) {
    dfn[v] = low[v] = ++dep;
    sta.push(v);
    mark[v] = true;
    int k;
    for (k = head[v]; k != -1; k = next[k]) {
        if (!dfn[to[k]]) {
            tarjan(to[k]);
            low[v] = min(low[v], low[to[k]]);
        } else if (mark[to[k]]) {
            low[v] = min(low[v], dfn[to[k]]);
        }
    }
    if (low[v] == dfn[v])  {
        ++scc;
        int u;
        do {
            u = sta.top();
            sta.pop();
            mark[u] = false;
            id[u] = scc;
        } while(u != v);
    }
}


int main(){
#ifndef ONLINE_JUDGE
    freopen("1.txt", "r", stdin);
#endif
    int i, j, k, u, v;
    int n, m;
    while(cin >> n >> m) {
        memset(head, -1, sizeof(head));
        memset(dfn, 0, sizeof(dfn));
        memset(mark, false, sizeof(mark));
        while(!sta.empty()){
            sta.pop();
        }
        dep = 1;
        for (i = 0; i < m; i++) {
            scanf("%d%d", &u, &v);
            to[i] = v;
            next[i] = head[u];
            head[u] = i;
        }
        scc = 0;
        for (i = 1; i <= n; i++) {
            if (!dfn[i]) {
                tarjan(i);
            }
        }
        memset(mark, false, sizeof(mark));
        for (i = 1; i <= n; i++) {
            for (j = head[i]; j != -1; j = next[j]) {
                if (id[i] != id[to[j]]) {
                    mark[id[i]] = true;
                }
            }
        }
        int p;
        int cnt = 0;
        for (i = 1; i <= scc; i++) {
            if (!mark[i]) {
                cnt++;
                p = i;
            }
        }
        if (cnt > 1) {
            printf("0\n");
        } else {
            cnt = 0;
            for (i = 1; i <= n; i++) {
                if (id[i] == p) {
                    cnt++;
                }
            }
            cout << cnt << endl;
        }
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值