POJ 2186(有向图缩点)

题目描述:

 有n(n<=10000)头牛,给出m(m<=50000)个关系(x,y),表示牛x认为牛y很popular。

如果牛x认为牛y很popular,而且牛y认为牛z很popular,则牛x认为牛z很popular。

问被其他所有牛都认为很popular的牛有多少头。

题目分析:

转化为有向图。进行强连通缩点(一个强连通分量内的牛互相都认为对方popular)

如果只有一个强连通分量出度为0,则这个强连通分量的点的数量为答案

如果有多个强连通分量出度为零,则答案为0(一个出度为0的强连通分量内的牛,都不认为其他分量的牛是popular的,反之亦然)

代码:

#include <stdio.h>
#include <math.h>
#include <string.h>
#include <algorithm>
#include <iostream>
#include <queue>
#include <stack>
#include <functional>
#define INF 0x3f3f3f3f
#define P (1000000007)
using namespace std;
typedef long long ll;
struct edge{
    int u, v, next;
}g[50010];
int n, m, head[10010], vis[10010], dfn[10010], low[10010], dep;
int cnt, belong[10010], chudu[10010];/*缩后强连通分量数  各点所在强连通分量标记  各强连通分量出度*/
stack<int> stk;
void dfs(int u){
    vis[u] = 1;
    dfn[u] = low[u] = ++dep;
    stk.push(u);
    for (int i = head[u]; i != -1; i = g[i].next){
        int v = g[i].v;
        if (!vis[v]){
            dfs(v);
            low[u] = min(low[u], low[v]);
        }
        else if (belong[v]==0)   /*该点还不属于任何强连通分量*/
            low[u] = min(low[u], dfn[v]);
    }
    if (low[u] == dfn[u]){
        ++cnt;
        while (1){
            int d = stk.top();
            belong[d] = cnt;
            stk.pop();
            if (d == u)break;
        }
    }
}
int main(){
    int u, v, ans;
    while (~scanf("%d %d", &n, &m)){
        memset(head, -1, sizeof(head));
        memset(vis, 0, sizeof(vis));
        memset(dfn, 0, sizeof(dfn));
        memset(low, 0, sizeof(low));
        memset(belong, 0, sizeof(belong));
        memset(chudu, 0, sizeof(chudu));
        ans = dep = cnt = 0;
        while (stk.size())stk.pop();
        for (int i = 0; i < m; i++){
            scanf("%d %d", &u, &v);
            g[i].u = u;
            g[i].v = v;
            g[i].next = head[u];
            head[u] = i;
        }
        for (int i = 1; i <= n; i++)
            if (vis[i] == 0)
                dfs(i);
        for (int i = 0; i < m; i++)
            if (belong[g[i].u] != belong[g[i].v]){
                chudu[belong[g[i].u]]++;
            }
        for (int i = 1; i <= cnt; i++){
            if (chudu[i] == 0){
                if (ans == 0){
                    for (int j = 1; j <= n; j++){
                        if (belong[j] == i)
                            ans++;
                    }
                }
                else{ /*若出度为0的点数不止一个,则答案为0*/
                    ans = 0;
                    break;
                }
            }
        }
        printf("%d\n", ans);
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/kzn2683331518/article/details/81139839
今日推荐