码迷,mamicode.com
首页 > 其他好文 > 详细

hdu3639Hawk-and-Chicken(无向图缩点+dfs)

时间:2021-04-05 12:24:28      阅读:0      评论:0      收藏:0      [点我收藏+]

标签:ems   模板   ble   tar   sel   inner   才有   any   efs   

题目描述:

Kids in kindergarten enjoy playing a game called Hawk-and-Chicken. But there always exists a big problem: every kid in this game want to play the role of Hawk.
So the teacher came up with an idea: Vote. Every child have some nice handkerchiefs, and if he/she think someone is suitable for the role of Hawk, he/she gives a handkerchief to this kid, which means this kid who is given the handkerchief win the support. Note the support can be transmitted. Kids who get the most supports win in the vote and able to play the role of Hawk.(A note:if A can win
support from B(A != B) A can win only one support from B in any case the number of the supports transmitted from B to A are many. And A can‘t win the support from himself in any case.
If two or more kids own the same number of support from others, we treat all of them as winner.
Here‘s a sample: 3 kids A, B and C, A gives a handkerchief to B, B gives a handkerchief to C, so C wins 2 supports and he is choosen to be the Hawk.

题目大意:小孩子们都想当队长,但是不可能所有人都满足,所以小孩子们会选择一些人来认为他可以当队长(和我小学五六年级选班长好像~),

但是不是单纯的统计票数,票数是可以传递的,比如有1-2,2-3,那么3的得票就是2,让我们求出最多得票数,以及可以当选队长的人。

思路:在环中的节点的得票最少都是环中节点个数-1(自己),所以我们先缩点,把所有强连通(环)中的点的个数的出来,并重新建图,再从新的图中

找到那些入读为0的点(这些点才有可能成为队长)dfs下去求出他的得票,并记录最大值,最后把得票与最大值相同的点输出即可。

dfs一定要刷新vis数组,重新查找一遍,因为这不是树!

AC代码:

#include<bits/stdc++.h>
using namespace std;
const int maxn = 50100;
typedef long long ll;
struct edge {
    int f, t, nxt;
}e[maxn << 1];
int hd[maxn], tot;
void add(int f, int t) {
    e[++tot] = { f,t,hd[f] };
    hd[f] = tot;
}
int n, m;
int low[maxn], dfn[maxn], cnt;
int stk[maxn], sk, instk[maxn];
int col[maxn], colnum;
int du[maxn], num[maxn], vis[maxn];;
int sa[maxn];
void init() {
    memset(hd, 0, sizeof(hd));
    memset(dfn, 0, sizeof(dfn));
    memset(col, 0, sizeof(col));
    memset(du, 0, sizeof(du));
    memset(num, 0, sizeof(num));
    memset(vis, 0, sizeof(vis));
    memset(sa, 0, sizeof(sa));
    cnt = sk = colnum = tot = 0;
}
void tarjan(int u) {//有向图缩点模板
    low[u] = dfn[u] = ++cnt;
    stk[++sk] = u; instk[u] = 1;
    for (int i = hd[u]; i; i = e[i].nxt) {
        int v = e[i].t;
        if (!dfn[v]) {
            tarjan(v);
            low[u] = min(low[u], low[v]);
        }
        else if (instk[v]) {
            low[u] = min(low[u], dfn[v]);
        }
    }
    if (low[u] == dfn[u]) {
        colnum++;
        while (1) {
            int v = stk[sk--];
            instk[v] = 0;
            num[colnum]++;
            //该连通分量中的节点个数,然后后面可以直接用来dfs
            col[v] = colnum;//标记属于那个连通分量
            if (v == u)break;
        }
    }
}
void dfs(int u,int rt) {
    if (vis[u])return;
    vis[u] = 1;
    sa[rt] += num[u];
    for (int i = hd[u]; i; i = e[i].nxt) {
        int v = e[i].t;
        dfs(v,rt);
    }
}
int main() {
    //freopen("test.txt", "r", stdin);
    int t; scanf("%d", &t);
    for (int cse = 1; cse <= t; cse++) {
        scanf("%d%d", &n, &m);
        init();
        for (int i = 1; i <= m; i++) {
            int a, b; scanf("%d%d", &a, &b);
            add(b, a);
        }
        for (int i = 0; i < n; i++) {
            if (!dfn[i]) {
                tarjan(i);
            }
        }
        memset(hd, 0, sizeof(hd)); tot = 0;
        //直接用之前的数组来存,难得多开了。
        for (int i = 1; i <= m; i++) {//缩点
            int u = e[i].f, v = e[i].t;
            if (col[u] != col[v]) {
                add(col[u], col[v]);
                du[col[v]]++;
            }
        }//缩点部分应该都没错,我一直用的这个板子
        int ans = 0;
        for (int i = 1; i <= colnum; i++) {//缩点后的DAG图找入读为0的点dfs下去
            if (du[i] == 0) {
                memset(vis, 0, sizeof(vis));
                dfs(i,i);
                sa[i]--;//减去自己
                ans = max(ans, sa[i]);
            }
        }
        printf("Case %d: %d\n", cse, ans);
        set<int>rescol;
        for (int i = 1; i <= colnum; i++) {//找的票与最大值相同的分组(强连通分量)
            if (sa[i]== ans) {
                rescol.insert(i);
            }
        }
        bool h = 0;
        for (int i = 0; i < n; i++) {//如果自己所在的分组是的票最多的就输出
            if (rescol.count(col[i])) {
                if (h)printf(" ");
                printf("%d", i);
                h = 1;
            }
        }
        printf("\n");
    }
    return 0;
}

 

hdu3639Hawk-and-Chicken(无向图缩点+dfs)

标签:ems   模板   ble   tar   sel   inner   才有   any   efs   

原文地址:https://www.cnblogs.com/MYMYACMer/p/14613206.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!