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

http://acm.hdu.edu.cn/showproblem.php?pid=3639

题意:

有一群孩子正在玩老鹰抓小鸡,由于想当老鹰的人不少,孩子们通过投票的方式产生,但是投票有这么一条规则:投票具有传递性,A支持B,B支持C,那么C获得2票(A.B共两票),输出最多能获得的票数是多少张和获得最多票数的人是谁?

思路:

先强连通缩点反向建图,在计算强连通的时候,需要保存每个连通分支的结点个数。

为什么要反向建图呢?因为要寻找票数最多的,那么肯定是入度为0的点,然后dfs计算它的子节点的权值(连通分支结点个数)加起来有多少。

注意,最后要减去1,不能把自己也算进去。

  1 #include<iostream>
  2 #include<algorithm>
  3 #include<cstring>
  4 #include<cstdio>
  5 #include<vector>
  6 #include<queue>
  7 #include<cmath>
  8 #include<stack>
  9 using namespace std;
 10 
 11 const int maxn=5000+5;
 12 
 13 int n,m;
 14 int sum;
 15 
 16 vector<int> G[maxn];
 17 int pre[maxn],lowlink[maxn],sccno[maxn],dfs_clock,scc_cnt;
 18 int num[maxn];   //记录每个连通分支的结点个数
 19 stack<int> S;
 20 
 21 vector<int> rG[maxn];
 22 int in[maxn];
 23 int vis[maxn];
 24 int cnt[maxn];
 25 
 26 void dfs(int u) {
 27     pre[u] = lowlink[u] = ++dfs_clock;
 28     S.push(u);
 29     for (int i = 0; i < G[u].size(); i++)
 30     {
 31         int v = G[u][i];
 32         if (!pre[v])
 33         {
 34             dfs(v);
 35             lowlink[u] = min(lowlink[u], lowlink[v]);
 36         }
 37         else if(!sccno[v])
 38         lowlink[u] = min(lowlink[u], pre[v]);
 39     }
 40     if (pre[u] == lowlink[u])
 41     {
 42         scc_cnt++;
 43         num[scc_cnt]=0;
 44         for(;;)
 45         {
 46             int x = S.top(); S.pop();
 47             sccno[x] = scc_cnt;
 48             num[scc_cnt]++;
 49             if (x == u) break;
 50         }
 51     }
 52 }
 53 
 54 void find_scc(int n)
 55 {
 56     dfs_clock = scc_cnt = 0;
 57     memset(pre, 0, sizeof(pre));
 58     memset(sccno, 0, sizeof(sccno));
 59     for (int i = 0; i < n; i++)
 60         if (!pre[i]) dfs(i);
 61 }
 62 
 63 void dfs2(int u)
 64 {
 65     vis[u]=1;
 66     sum+=num[u];  
 67     for(int i=0;i<rG[u].size();i++)
 68     {
 69         int v=rG[u][i];
 70         if(!vis[v])  dfs2(v);
 71     }
 72 }
 73 
 74 int main()
 75 {
 76     //freopen("D:\input.txt","r",stdin);
 77     int T;
 78     int kase=0;
 79     scanf("%d",&T);
 80     while(T--)
 81     {
 82         scanf("%d%d",&n,&m);
 83         for(int i=0;i<n;i++)  G[i].clear();
 84         while(m--)
 85         {
 86             int u,v;
 87             scanf("%d%d",&u,&v);
 88             G[u].push_back(v);
 89         }
 90         find_scc(n);
 91 
 92         for(int i=1;i<=scc_cnt;i++)  rG[i].clear();
 93         memset(in,0,sizeof(in));
 94         for(int u=0;u<n;u++)
 95         {
 96             for(int i=0;i<G[u].size();i++)
 97             {
 98                 int v=G[u][i];
 99                 if(sccno[u]!=sccno[v])  {rG[sccno[v]].push_back(sccno[u]);in[sccno[u]]++;}
100             }
101         }
102 
103         int ans=0;
104         memset(cnt,0,sizeof(cnt));
105         for(int i=1;i<=scc_cnt;i++)
106         {
107             sum=0;
108             if(in[i]==0)  //入度为0
109             {
110                 memset(vis,0,sizeof(vis));
111                 dfs2(i);
112                 cnt[i]=sum-1;   //需要减1,因为它自己所处的连通分支得把自己减去
113                 ans=max(sum-1,ans);
114             }
115         }
116         printf("Case %d: %d
",++kase,ans);
117         bool flag=true;
118         for(int i=0;i<n;i++)
119         {
120             if(cnt[sccno[i]]==ans)
121             {
122                 if(flag)  {printf("%d",i);flag=false;}
123                 else      printf(" %d",i);
124             }
125         }
126         printf("
");
127     }
128     return 0;
129 }
原文地址:https://www.cnblogs.com/zyb993963526/p/6817357.html