[HAOI2006 受欢迎的牛] 强联通分量 缩点

From:http://www.lydsy.com/JudgeOnline/problem.php?id=1051

Solution:

1.根据题目描述建立图G, 对于任意(a,b)属于G, 表示a认为b受欢迎

2.显然, 对于任意的强联通分量C, 对任意(a,b)属于C, a,b都是C中受欢迎的

3.缩点,建立SCC图,在原图G中的任意边(a,b), 反向后得到SCC图,显然SCC图是一个有向无回路图。现在,解规约为一个判定性问题: SCC图中是否存在一个点u, u可达SCC图中的所有顶点?

4.判断是否存在这样的顶点

/**************************************************************
    Problem: 1051
    User: leezy
    Language: C++
    Result: Accepted
    Time:80 ms
    Memory:2364 kb
****************************************************************/
 
#include <algorithm>
#include <stdio.h>
#include <string.h>
#include <time.h>
#include <stdlib.h>
#include <queue>
#include <stack>
#include <functional>
using namespace std;
#define N 10005
#define M 50005
#define INF 0x6fffffff
#define MAX_LEVEL 32
#define NIL (-1)
#define lowbit(i) ((i)&(-i))
std::stack<int> sta;
struct { int to,next; } nod[M*2];
bool isIn[N];
int adj[N], low[N], d[N], scc[N], scc_adj[N], ind[N], num[N], scc_cnt, now, reach, t;
void init(int n){
    now = scc_cnt = reach = t = 0;
    for (int i = 0; i <= n; ++i){
        d[i] = low[i] = INF;
        ind[i] = num[i] = 0;
        isIn[i] = false;
        adj[i] = scc[i] = scc_adj[i] =NIL;
    }
}
void add(int u, int v){
    nod[++now].to = v;
    nod[now].next = adj[u]; adj[u] = now;
}
void add_scc(int u, int v){
    nod[++now].to = v;
    nod[now].next = scc_adj[u]; scc_adj[u] = now;
}
void tarjan(int u){
    low[u] = d[u] = t = t + 1;
    sta.push(u); isIn[u] = true;
    for (int i = adj[u]; i != NIL; i = nod[i].next){
        int v = nod[i].to;
        if ( d[v] == INF ){
            tarjan(v);
            low[u] = min(low[u], low[v]);
        } else if ( isIn[v] ){
            low[u] = min(d[v], low[u]);
        }
    }
    if ( low[u] == d[u] ){
        while ( !sta.empty() ){
            int v = sta.top(); sta.pop();
            isIn[v] = false;
            scc[v] = scc_cnt;
            ++num[scc_cnt];
            if ( v == u ) break;
        }
        ++scc_cnt;
    }
}
void dfs(int u){
    ++reach;
    isIn[u] = true;
    for (int i = scc_adj[u]; i != NIL; i = nod[i].next){
        int v = nod[i].to;
        if ( !isIn[v] ) dfs(v);
    }
}
int run(int n){
    for (int i = 0; i < n; ++i) if ( d[i] == INF ) tarjan(i);
    for (int i = 0; i < n; ++i)
    for (int j = adj[i]; j != NIL; j = nod[j].next){
        int I = scc[i], J = scc[nod[j].to];
        if ( I != J ) add_scc(J,I);
    }
    for (int i = 0; i < scc_cnt; ++i){
        isIn[i] = false;
        for (int j = scc_adj[i]; j != NIL; j = nod[j].next) ++ind[nod[j].to];
    }
    int u = 0;
    for (int i = 0; i < scc_cnt; ++i) if ( !ind[i] ){ u = i; break; }
    dfs(u);
    return reach >= scc_cnt?num[u]:0;
}
int main()
{
    //const char path[] = "D:\\Project\\AlgorithmExam\\test.txt";
    //freopen(path, "r+", stdin);
 
    int n,m;
    while( scanf("%d%d", &n, &m) != EOF ){
        init(n);
        for (int i = 0; i < m; ++i){
            int a,b;
            scanf("%d%d", &a, &b);
            add(a-1,b-1);
        }
        printf("%d\n", run(n));
    }
    return 0;
}
View Code

 

posted on 2013-12-07 23:33  leezyli  阅读(143)  评论(0编辑  收藏  举报

导航