HDU 3639 Hawk-and-Chicken 强联通缩点 + DFS

来源:互联网 发布:剑侠情缘手游工资算法 编辑:程序博客网 时间:2024/05/17 17:42

题意:n个小朋友传递手帕,如果A传递给B B传递给C 那么C会得到A和B的手帕,问你那些小朋友会得到最多种类的手帕(不算自己的手帕)。

思路:对于在同一个强联通分量的小朋友,他们得到的手帕数量是相同的,都为所在联通分量点数减一,我们将其缩点,得到一个DAG,剩下的就是计算出度为零的小朋友会得到多少种手帕,正着找不好找,我们将所有边反向,从终点找所有能遍历到的点,更新最大值即可。

#include <cstdio>#include <cstring>#include <algorithm>#include <vector>#include <queue>using namespace std;#define REP( i, a, b ) for( int i = a; i < b; i++ )#define CLR( a , x ) memset( a , x , sizeof a )const int maxn = 5000 + 10;const int maxe = 100000 + 10;struct Edge{    int v, next;    Edge (int v = 0, int next = 0) : v(v), next(next) {}};struct SCC{    int Head[maxn], cntE;    int dfn[maxn], low[maxn], dfs_clock;    int scc[maxn], scc_cnt;    int Stack[maxn], top;    bool ins[maxn];    Edge edge[maxe];    void init(){        top = 0;        cntE = 0;        scc_cnt = 0;        dfs_clock = 0;        CLR(ins, 0);        CLR(dfn, 0);        CLR(Head, -1);    }    void add(int u, int v){        edge[cntE] = Edge(v, Head[u]);        Head[u] = cntE++;    }    void Tarjan(int u){        dfn[u] = low[u] = ++dfs_clock;        Stack[top++] = u;        ins[u] = 1;        for (int i = Head[u] ; ~i ; i = edge[i].next){            int v = edge[i].v;            if (!dfn[v]){                Tarjan (v) ;                low[u] = min(low[u], low[v]) ;            }            else if (ins[v])                low[u] = min (low[u], dfn[v]) ;        }        if (low[u] == dfn[u]){            ++scc_cnt;            while ( 1 ){                int v = Stack[--top];                ins[v] = 0;                scc[v] = scc_cnt;                if (v == u)                    break;            }        }    }    void find_scc(int n){        REP(i, 0, n) if(!dfn[i]) Tarjan (i) ;    }}scc;Edge e[maxe];int cnte, H[maxn];int cost[maxn], in[maxn];int ANS[maxn];int cur_cost[maxn];int vis[maxn];int n, m;vector<int> ans_scc;void Init(){    memset(H, -1, sizeof(H));    memset(cost , 0, sizeof(cost));    memset(ANS, 0, sizeof(ANS));    memset(in, 0, sizeof(in));    cnte = 0;    ans_scc.clear();}void Add(int u, int v){    e[cnte] = Edge(v, H[u]);    H[u] = cnte++;}int cur_sum;void dfs(int u){    for(int i = H[u]; ~i; i = e[i].next){        int v = e[i].v;        if(!vis[v]){            vis[v] = 1;            cur_sum += cost[v];            dfs(v);        }    }}int cas = 0;void solve(){    scanf("%d%d", &n, &m);    scc.init();    for(int i = 0; i < m; i++){        int u, v;        scanf("%d%d", &u, &v);        scc.add(u, v);    }    scc.find_scc(n);    Init();    for(int i = 0; i < n; i++)    for(int j = scc.Head[i]; ~j; j = scc.edge[j].next){        int u = i, v = scc.edge[j].v;        if(scc.scc[u] != scc.scc[v]){            Add(scc.scc[v], scc.scc[u]);            in[scc.scc[u]]++;        }    }    for(int i = 0; i < n; i++)        cost[scc.scc[i]]++;    int ans = 0;    for(int i = 1; i <= scc.scc_cnt; i++)        if(!in[i]){            cur_sum = cost[i];            memset(vis, 0, sizeof(vis));            dfs(i);            ANS[i] = cur_sum;            ans = max(ans, cur_sum);        }    int f = 0;    printf("Case %d: %d\n", ++cas, ans - 1);    for(int i = 0; i < n; i++){        if(ANS[scc.scc[i]] == ans){            if(f) printf(" "); f = 1;            printf("%d", i);        }    }    printf("\n");}int main(){    //freopen("in.txt", "r", stdin);    int T;    scanf("%d", &T);    while(T--) solve();    return 0;}
0 0
原创粉丝点击