现在的位置: 首页 > 综合 > 正文

poj 2186 Popular Cows

2017年10月18日 ⁄ 综合 ⁄ 共 1636字 ⁄ 字号 评论关闭

n(1<=n<=10000) 头牛,有 m(1<=m<=50000) 个推举关系。推举关系具有传递性,即 A 推举 B, B 推举 C,那么 A 也推举 C

问你,能够得到所有牛推举的牛有多少头?


题解:强连通分支+缩点

强连通分支为最大的连通子图,在这个子图中任意两点都是可达的。

在一个强连通分支里面,根据推举关系可知,这个强连通分支里的所有的牛都能得到其他所有的牛的推举。

我们将题目给的推举关系,看成是牛群推举图里的一条边,而且是有向的,而且可以有环。

对于环,在环中的任意点,环中其它的点都是可以到达这个点的。

而这个环就相当于一个强连通分支。

而缩点的意义在于,我们可以将推举图变成推举树,这样做的意义在于,如果这棵树的叶子节点只有一个,则这个节点在原推举图中包含了多少个点,那么其值就是我们要求的答案。如果这棵树的叶子节点大于一个,那么答案肯定为0.

因此,此题有三个步骤是关键,一,求强连通分支,二、将强连通分支缩成点。三、求叶子节点

对于一、求强连通分支的方法又tarjan算法

对于二、我们可以在tarjan算法里增加一段缩点代码。就是在找到强连通分支的时候。

对于三、只要出度为0,就是叶子节点。


代码:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <vector>
#include <stack>
using namespace std;

const int  MAX_  = 10010;
typedef long long LL;

vector<int>arc[MAX_];
stack<int>s;
int dfn[MAX_], low[MAX_], cnt[MAX_], id[MAX_];
int n, m, T, ind;
bool vs[MAX_];

void tarjan(int u){
    vs[u] = 1, s.push(u);
    dfn[u] = low[u] = T++;
    int len = (int)arc[u].size();
    for(int i = 0; i < len; i++){
        int v = arc[u][i];
        if(dfn[v] == -1){
            tarjan(v);
            if(low[u] > low[v]) low[u] = low[v];
        }
        else if(vs[v] && dfn[v] < low[u]) low[u] = dfn[v];
    }
    if(dfn[u] == low[u]){
        for(int v; 1 ;){
            v = s.top();
            s.pop();vs[v] = 0;
            cnt[ind]++,id[v] = ind;
            if(u == v)break;
        }
        ind++;
    }
}


int main() {
    //int Case, n, h,v, tmp, maxh,minh, maxv,minv;
    //int x1,y1,x2,y2;
    scanf("%d%d",&n,&m);
    for(int i = 0; i <= n; i++)arc[i].clear();
    for(int i = 0, a, b; i < m; i++){
        scanf("%d%d",&a,&b);
        arc[a].push_back(b);
    }
    for(int i = 0; i <= n; i++)vs[i] = 0, dfn[i] = -1,cnt[i] = 0;
    while(!s.empty())s.pop();

    T= ind = 0;
    for(int i = 1; i <= n; i++){
        if(dfn[i] == -1)tarjan(i);
    }
    for(int i = 0; i < ind; i++)dfn[i] = 0;

    for(int i = 1; i <= n ; i++){
        int len = (int) arc[i].size(), u= id[i];
        for(int j = 0; j < len; j++){
            int v = id[arc[i][j]];
            if(u != v)dfn[u]++;
        }
    }
    int ans =0,flag =0;
    for(int i = 0; i < ind; i++){
        if(dfn[i] == 0){
            ans = cnt[i];
            flag ++;
            if(flag > 1)break;
        }
    }
    if(flag != 1)ans = 0;
    printf("%d\n",ans);

    return 0;
}

抱歉!评论已关闭.