HDU 3639 Hawk-and-Chicken(强连通分量+缩点)

来源:互联网 发布:浙江网络诈骗立案标准 编辑:程序博客网 时间:2024/06/06 04:25

题意:给你一个有向图,如果从u点能到达v点,那么说u是v的粉丝,现在要你按序输出那些粉丝数目最多的点编号.

思路:转自网上,写得很详细了

          假设该图是一个强连通图,那么任一点都有n-1个粉丝(即n-1个点能到达它).所以我们把该图缩点变成一个新的DAG图.

          结论:原图中具有最多粉丝的点一定在新图的那些出度为0的点所代表的分量中.

          证明:假设u节点粉丝最多且它所属的分量出度不为0,那么u节点一定是某个节点v的粉丝,所以v的粉丝必然包含了u的所有粉丝加上u本身.所以v的粉丝必然多余u.由此矛盾.

         下面的问题是如何找新DAG图的每个节点(所代表分量中的原节点)的最大粉丝数? 该粉丝数=本连通分量的点数-1+本连通分量能通过ß这种边逆向走到的所有分量的点数和. 所以我们直接建立缩点树的逆图DAG即可,如果u->v表示u分量将获得v分量的所有节点作为粉丝.所以我们只需要对那几个入度为0的点做DFS即可.

         每次DFS到一个新节点,该点所代表的分量节点数就都加到sum上去,表示新加了很多粉丝.最后找最大粉丝值的分量点输出即可.



#include <cstdio>#include <queue>#include <cstring>#include <iostream>#include <cstdlib>#include <algorithm>#include <vector>#include <map>#include <string>#include <set>#include <ctime>#include <cmath>#include <cctype>#include <stack>using namespace std;#define maxn 100000+100#define LL long longint cas=1,T;vector<int>G[maxn],NewG[maxn];int pre[maxn];int lowlink[maxn];int sccno[maxn];int num[maxn];            //在i编号scc中有多少个点int dfs_clock,scc_cnt;int n,m;int fan[maxn];            //新的图中每个点的粉丝数stack<int>S;void dfs(int u){pre[u]=lowlink[u]=++dfs_clock;S.push(u);for (int i = 0;i<G[u].size();i++){int v = G[u][i];if (!pre[v]){dfs(v);lowlink[u] = min(lowlink[u],lowlink[v]);}else if (!sccno[v]){lowlink[u] = min (lowlink[u],pre[v]);}}if (lowlink[u] == pre[u]){scc_cnt++;//num[scc_cnt]=0;for (;;){int x = S.top();S.pop();sccno[x] = scc_cnt;num[scc_cnt]++;if (x==u)break;}}}void find_scc(int n){dfs_clock=scc_cnt=0;memset(sccno,0,sizeof(sccno));memset(pre,0,sizeof(pre));for (int i = 0;i<n;i++)if (!pre[i])dfs(i);}int in[maxn];int out[maxn];bool vis[maxn];int dfs2(int u){vis[u]=1;int sum = 0;for (int i = 0;i<NewG[u].size();i++){int v = NewG[u][i];if (!vis[v])sum+=num[v]+dfs2(v);}return sum;}int main(){//freopen("in","r",stdin);scanf("%d",&T);while (T--){//printf("Case %d: ",cas++);scanf("%d%d",&n,&m);for (int i = 0;i<=n;i++)G[i].clear();memset(out,0,sizeof(out));memset(in,0,sizeof(in));memset(num,0,sizeof(num));for (int i = 1;i<=m;i++){int u,v;scanf("%d%d",&u,&v);G[u].push_back(v);}find_scc(n);for (int i = 0;i<=scc_cnt;i++){            out[i]=0;in[i]=0;NewG[i].clear();}for (int u = 0;u<n;u++)for (int i =0;i<G[u].size();i++){int v = G[u][i];if (sccno[u] != sccno[v]){        NewG[sccno[v]].push_back(sccno[u]);in[sccno[u]]++;}}memset(fan,0,sizeof(fan));int maxf=-1;for (int i = 1;i<=scc_cnt;i++){if (!in[i]){memset(vis,0,sizeof(vis));fan[i]=num[i]-1+dfs2(i);maxf=max(fan[i],maxf);}}bool win[maxn];memset(win,0,sizeof(win));for (int i = 0;i<n;i++)if (fan[sccno[i]]==maxf)win[i]=1;printf("Case %d: %d\n",cas++,maxf);bool first = 1;for (int i = 0;i<n;i++)if (win[i]){if (first)printf("%d",i),first=0;elseprintf(" %d",i);}   puts("");}return 0;}



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 total supports 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

24 33 22 02 13 31 02 10 2
 

Sample Output

Case 1: 20 1Case 2: 20 1 2
 


0 0
原创粉丝点击