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

题意: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
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值