HDU 3639 Hawk-and-Chicken(Tarjan缩点+反向DFS)

Problem Description

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.

Input

There are several test cases. First is a integer T(T <= 50), means the number of test cases.

Each test case start with two integer n, m in a line (2 <= n <= 5000, 0 <m <= 30000). n means there are n children(numbered from 0 to n - 1). Each of the following m lines contains two integers A and B(A != B) denoting that the child numbered A give a handkerchief
to B.

Output

For each test case, the output should first contain one line with "Case x:", here x means the case number start from 1. Followed by one number which is the totalsupports the winner(s) get.

Then follow a line contain all the Hawks‘ number. The numbers must be listed in increasing order and separated by single spaces.

Sample Input

2
4 3
3 2
2 0
2 1

3 3
1 0
2 1
0 2

Sample Output

Case 1: 2
0 1
Case 2: 2
0 1 2

题意:选出人当老鹰:类似A->B,B->C=>A->C的,最后谁得到的多就选谁。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<limits.h>
typedef long long LL;
using namespace std;

#define REPF( i , a , b ) for ( int i = a ; i <= b ; ++ i )
#define REP( i , n ) for ( int i = 0 ; i < n ; ++ i )
#define CLEAR( a , x ) memset ( a , x , sizeof a )

const int maxn=5000+100;
const int maxm=100000+10;
struct node{
    int u,v;
    int next;
}e[maxm],e1[maxn];
int head[maxn],cntE,cntF;
int DFN[maxn],low[maxn],h[maxn];
int s[maxm],top,index,cnt;
int belong[maxn],instack[maxn];
int dp[maxn],in[maxn],vis[maxn];
int num[maxn];
int n,m;
void init()
{
    top=cntE=cntF=0;
    index=cnt=0;
    CLEAR(DFN,0);
    CLEAR(head,-1);
    CLEAR(instack,0);
}
void addedge(int u,int v)
{
    e[cntE].u=u;e[cntE].v=v;
    e[cntE].next=head[u];
    head[u]=cntE++;
}
void Tarjan(int u)
{
    DFN[u]=low[u]=++index;
    instack[u]=1;
    s[top++]=u;
    for(int i=head[u];i!=-1;i=e[i].next)
    {
        int v=e[i].v;
        if(!DFN[v])
        {
            Tarjan(v);
            low[u]=min(low[u],low[v]);
        }
        else if(instack[v])
            low[u]=min(low[u],DFN[v]);
    }
    int v;
    if(DFN[u]==low[u])
    {
        cnt++;
        do{
            v=s[--top];
            belong[v]=cnt;
            instack[v]=0;
        }while(u!=v);
    }
}
int dfs(int x)
{
    int ans=num[x];
    for(int i=h[x];i!=-1;i=e1[i].next)
    {
        int v=e1[i].v;
        if(!vis[v])
        {
            vis[v]=1;
            ans+=dfs(v);
        }
    }
    return ans;
}
void work()
{
    REP(i,n)
      if(!DFN[i])  Tarjan(i);
   if(cnt==1)
   {
       printf("%d\n",n-1);
       REP(i,n)
        printf(i==n-1?"%d\n":"%d ",i);
       return ;
   }
   CLEAR(num,0);
   CLEAR(dp,0);
   CLEAR(in,0);
   CLEAR(h,-1);
   REP(i,n)//马丹,这里卡了我两天
     num[belong[i]]++;
   REP(k,n)
   {
       for(int i=head[k];i!=-1;i=e[i].next)
       {
         int v=e[i].v;
         if(belong[k]!=belong[v])//反向建边dfs.
         {
//           cout<<"666  "<<endl;
           e1[cntF].u=belong[v];
           e1[cntF].v=belong[k];
           e1[cntF].next=h[belong[v]];
           h[belong[v]]=cntF++;
           in[belong[k]]++;
         }
       }
   }
   REPF(i,1,cnt)
   {
       if(!in[i])
       {
         CLEAR(vis,0);
         dp[i]=dfs(i)-1;
       }
   }
    int ans=0;
    REPF(i,1,cnt)
      ans=max(ans,dp[i]);
    printf("%d\n",ans);
    int flag=0;
    REP(i,n)
    {
        if(dp[belong[i]]==ans)
        {
           if(!flag)
              printf("%d",i),flag=1;
           else
              printf(" %d",i);
        }
    }
    printf("\n");
}
int main()
{
    int t,u,v;
    int cas=1;
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d%d",&n,&m);
        init();
        for(int i=0;i<m;i++)
        {
            scanf("%d%d",&u,&v);
            addedge(u,v);
        }
        printf("Case %d: ",cas++);
        work();
    }
    return 0;
}
时间: 2024-08-03 19:16:48

HDU 3639 Hawk-and-Chicken(Tarjan缩点+反向DFS)的相关文章

hihoCoder 1185 连通性&#183;三(Tarjan缩点+暴力DFS)

#1185 : 连通性·三 时间限制:10000ms 单点时限:1000ms 内存限制:256MB 描述 暑假到了!!小Hi和小Ho为了体验生活,来到了住在大草原的约翰家.今天一大早,约翰因为有事要出去,就拜托小Hi和小Ho忙帮放牧. 约翰家一共有N个草场,每个草场有容量为W[i]的牧草,N个草场之间有M条单向的路径. 小Hi和小Ho需要将牛羊群赶到草场上,当他们吃完一个草场牧草后,继续前往其他草场.当没有可以到达的草场或是能够到达的草场都已经被吃光了之后,小hi和小Ho就把牛羊群赶回家. 一开

HDU 3836 Equivalent Sets(Tarjan+缩点)

Problem Description To prove two sets A and B are equivalent, we can first prove A is a subset of B, and then prove B is a subset of A, so finally we got that these two sets are equivalent. You are to prove N sets are equivalent, using the method abo

HDU 3639 Hawk-and-Chicken (强连通分量+树形DP)

题目地址:HDU 3639 先用强连通分量缩点,缩点之后,再重新按缩点之后的块逆序构图,每个块的值是里边缩的点的个数,那么得到选票的最大的一定是重新构图后入度为0的块,然后求出来找最大值即可. 代码如下: #include <iostream> #include <string.h> #include <math.h> #include <queue> #include <algorithm> #include <stdlib.h>

HDU 3639 Hawk-and-Chicken tarjan缩点+dfs

题意:投票,投票可以传递,当一个人投票时,要把此人的得票数全给被投的那个人,问最后按升序输出得票数最高的人. 想法:显然在一个连通块内的所有点的得票数都是一样的,即:块内点数-1,(1:是他自己本身).所以先要tarjan缩点,然后求出每一个块可以由几个块到达(这里可以反向建边dfs).最后输出最大得票数的人即可. #include<iostream> #include<cstring> #include<cstdio> #include<stack> #i

[tarjan] hdu 3639 Hawk-and-Chicken

题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=3639 Hawk-and-Chicken Time Limit: 6000/2000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 1986    Accepted Submission(s): 575 Problem Description Kids in kindergarte

(tarjan/+DFS+反向建图) hdu 3639

G - Hawk-and-Chicken Time Limit:2000MS     Memory Limit:32768KB     64bit IO Format:%I64d & %I64u Submit Status Practice HDU 3639 Description Kids in kindergarten enjoy playing a game called Hawk-and-Chicken. But there always exists a big problem: ev

hdu 3639 有向图缩点+建反向图+搜索

题意:给个有向图,每个人可以投票(可以投很多人,一次一票),但是一个人只能支持一人一次,支持可以传递,自己支持自己不算,被投支持最多的人. 开始想到缩点,然后搜索,问题是有一点想错了!以为支持按票数计算,而不是按人数!还各种树形dp/搜索求可以到达边数..提交WA了... 又反复读了题目之后才发现..错误..只要人数就行...问题简单了许多... 缩点成有向无环图后:每个SCC中支持的人数就是scc里面的人,要求可到达的点最多的点,当然要放过来求方便:反向图那个点可以到达的点最多!于是建反向图直

HDU 3639 Hawk-and-Chicken(强连通缩点+反向建图)

http://acm.hdu.edu.cn/showproblem.php?pid=3639 题意: 有一群孩子正在玩老鹰抓小鸡,由于想当老鹰的人不少,孩子们通过投票的方式产生,但是投票有这么一条规则:投票具有传递性,A支持B,B支持C,那么C获得2票(A.B共两票),输出最多能获得的票数是多少张和获得最多票数的人是谁? 思路: 先强连通缩点反向建图,在计算强连通的时候,需要保存每个连通分支的结点个数. 为什么要反向建图呢?因为要寻找票数最多的,那么肯定是入度为0的点,然后dfs计算它的子节点的

HDU 2767 Proving Equivalences(强连通 Tarjan+缩点)

HDU 2767 Proving Equivalences(强连通 Tarjan+缩点) ACM 题目地址:HDU 2767 题意: 给定一张有向图,问最少添加几条边使得有向图成为一个强连通图. 分析: Tarjan入门经典题,用tarjan缩点,然后就变成一个有向无环图(DAG)了. 我们要考虑的问题是让它变成强连通,让DAG变成强连通就是把尾和头连起来,也就是入度和出度为0的点. 统计DAG入度和出度,然后计算头尾,最大的那个就是所求. 代码: /* * Author: illuz <iil