POJ-2186 Tarjan+缩点

Every cow’s dream is to become the most popular cow in the herd. In a herd of N (1 <= N <= 10,000) cows, you are given up to M (1 <= M <= 50,000) ordered pairs of the form (A, B) that tell you that cow A thinks that cow B is popular. Since popularity is transitive, if A thinks B is popular and B thinks C is popular, then A will also think that C is
popular, even if this is not explicitly specified by an ordered pair in the input. Your task is to compute the number of cows that are considered popular by every other cow.
Input

  • Line 1: Two space-separated integers, N and M

  • Lines 2…1+M: Two space-separated numbers A and B, meaning that A thinks B is popular.
    Output

  • Line 1: A single integer that is the number of cows who are considered popular by every other cow.
    Sample Input
    3 3
    1 2
    2 1
    2 3
    Sample Output
    1
    Hint
    Cow 3 is the only cow of high popularity.

题意

首先分析题目 牛之间的关系是可传递的 即这道题我们可以缩点 当我们缩完点后得到了一个AUG图 然后分析情况 当有一个入度为零的点时 我们有一个满足条件的答案 为什么呢 如果没有入度为零的点我们就没有一个拓扑序 那一定会形成环 那就与我们缩点的条件冲突 所以我们要找入度为零的点 当这种点有多个时 答案即为零 因为这两个点永远不会有联系 此外还有两种特殊情况 一种就是入度为零的点是我们的一个强连通分量构成的缩点 这个时候答案就是这个强连通分量的节点数 所以我们要在缩点时维护一个计算缩点后每个点所代表的点总数 还有一种就是图为一个强连通图 即缩点的点数为1 输出节点总数

一组数据

4 4
4 1
1 2
2 3
3 1
3

AC代码

#include<iostream>
#include<algorithm>
#include<string>
#include<map>
#include<set>
#include<map>
#include<set>
#include<queue>
#include<stack>
#include<vector>
#include<cstdlib>
#include<utility>
#include<cstring>
using namespace std;

const int INF = 0x3f3f3f3f;
const int maxn = 10010;
vector<int>G[maxn];
stack<int>sta;
set<int>se;
int dfn[maxn];
int low[maxn];
int id[maxn];
int flag,ans;
int m,n,tmpa,tmpb;
int in[maxn];
int out[maxn];
int size_tmp[maxn];

void Tarjan(int start){
    se.insert(start);
    sta.push(start);
    dfn[start] = low[start] = ++flag;
    size_t size_all = G[start].size();
    for(size_t i=0;i<size_all;++i){
        int x = G[start][i];
        if(dfn[x]==-1){
            Tarjan(x);
            low[start] = min(low[start],low[x]);
        }else if(se.find(x)!=se.end()){
            low[start] = min(low[start],low[x]);
        }
    }
    if(low[start] == dfn[start]){
        while(1){
            int tmp = sta.top();
            sta.pop();
            se.erase(tmp);
            id[tmp] = ans;
            size_tmp[ans]++;
            if(start == tmp) break;
        }
        ++ans;
    }
}

void solve(){
    int tmp = 0;
    int tep = 0;
    for(int i=1;i<=n;++i){
        int x = G[i].size();
        for(int j=0;j<x;++j){
            tmp = G[i][j];
            if(id[i] != id[tmp]){
                out[id[i]]++;
                in[id[tmp]]++;
            }
        }
    }
    int temp = 0;
    for(int i=0;i<ans;++i){
        if(out[i] == 0){
            ++tep;
            temp = size_tmp[i];
        }
    }
    if(ans == 1) cout << n << endl;//整个图被缩成一个点
    else if(tep == 1) cout << temp << endl;//有可能出现一种情况就是出度为零的点为一个强连通分量
    else cout << 0 << endl;
}

int main(){
    cin >> n >> m;
    for(int i=0;i<m;i++){
        cin >> tmpa >> tmpb;
        G[tmpa].push_back(tmpb);
    }
    memset(dfn,-1,sizeof(dfn));
    for(int i=1;i<=n;++i) if(dfn[i]==-1) Tarjan(i);
    solve();
    return 0;
}
posted @ 2022-07-02 13:18  李兆龙的博客  阅读(13)  评论(0编辑  收藏  举报