HDU 3639 HawkandChicken(强连通分量)

 

题目大意

 

有 n(2<=n<=5000) 个人,m(0<m<=30000) 个 support 关系(A support B)。问:哪些人得到的 support 最多。

需要注意的是 support 是可以传递的,比如:A support B && B support C,那么,C 得到的 support 是 2

 

做法分析

 

可以想到的是,枚举每个人得到的 support 的个数,这个做法是 o(n^2) 的。在 50 组数据的情况下,想要在 2s 内出结果,有点不现实

思来想去,这道题貌似没有什么好的做法

那么就想想怎么尽可能多的“剪枝”吧

        首先,如果一堆人中,每两个人都可以相互支持(间接或者直接),那么这一堆人可以缩成一个“人”。

        缩点之后,我们再反向建图,那么,能够得到最多的 support 的那一堆人,一定是图中入度为 0 的点

        对建好的图中那些入度为 0 的点,DFS 遍历一遍,得到 support 这个点的人数

找到 support 人数最多的点,输出组成这些点的人即可

 

参考代码

HDU 3639
  1 #include <cstdio>
  2 #include <algorithm>
  3 #include <cstring>
  4 #include <iostream>
  5 #include <stack>
  6 #include <vector>
  7 
  8 using namespace std;
  9 
 10 const int N=5006;
 11 
 12 stack <int> s;
 13 vector <int> adj[N], arc[N], com[N], ans;
 14 int n, m, t, ind, T, sum;
 15 int dfn[N], low[N], id[N], in[N];
 16 bool vs[N];
 17 
 18 void tarjan(int u)
 19 {
 20     dfn[u]=low[u]=T++;
 21     s.push(u), vs[u]=1;
 22     int len=(int)adj[u].size();
 23     for(int i=0; i<len; i++)
 24     {
 25         int v=adj[u][i];
 26         if(dfn[v]==-1)
 27         {
 28             tarjan(v);
 29             if(low[u]>low[v]) low[u]=low[v];
 30         }
 31         else if(vs[v] && low[u]>dfn[v]) low[u]=dfn[v];
 32     }
 33     if(low[u]==dfn[u])
 34     {
 35         for(int v; 1; )
 36         {
 37             v=s.top();
 38             s.pop(), vs[v]=0;
 39             id[v]=ind, com[ind].push_back(v);
 40             if(v==u) break;
 41         }
 42         ind++;
 43     }
 44 }
 45 
 46 void DFS(int u)
 47 {
 48     vs[u]=1;
 49     int len=(int)arc[u].size();
 50     sum+=(int)com[u].size(); // 可以优化
 51     for(int i=0; i<len; i++)
 52     {
 53         int v=arc[u][i];
 54         if(vs[v]) continue;
 55         DFS(v);
 56     }
 57 }
 58 
 59 int main()
 60 {
 61     scanf("%d", &t);
 62     for(int ca=1; ca<=t; ca++)
 63     {
 64         scanf("%d%d", &n, &m);
 65         for(int i=0; i<n; i++) adj[i].clear();
 66         for(int i=0, a, b; i<m; i++)
 67         {
 68             scanf("%d%d", &a, &b);
 69             adj[a].push_back(b);
 70         }
 71         for(int i=0; i<n; i++) vs[i]=0, dfn[i]=-1, com[i].clear();
 72         ind=T=0;
 73         while(!s.empty()) s.pop();
 74         for(int i=0; i<n; i++) if(dfn[i]==-1) tarjan(i);
 75         for(int i=0; i<ind; i++) arc[i].clear(), in[i]=0, dfn[i]=0;
 76         for(int i=0; i<n; i++)
 77         {
 78             int len=(int)adj[i].size();
 79             for(int j=0; j<len; j++)
 80             {
 81                 int v=id[adj[i][j]];
 82                 int u=id[i];
 83                 if(u!=v) arc[v].push_back(u), in[u]++;
 84             }
 85         }
 86         for(int i=0; i<ind; i++)
 87         {
 88             if(in[i]!=0) continue;
 89             for(int j=0; j<ind; j++) vs[j]=0;
 90             sum=0;
 91             DFS(i);
 92             dfn[i]=sum;
 93         }
 94         int Max=-0x3fffffff;
 95         for(int i=0; i<ind; i++)
 96             if(Max<dfn[i]) Max=dfn[i];
 97         ans.clear();
 98         for(int i=0; i<ind; i++)
 99         {
100             if(dfn[i]!=Max) continue;
101             int len=(int)com[i].size();
102             for(int j=0; j<len; j++) ans.push_back(com[i][j]);
103         }
104         sort(ans.begin(), ans.end());
105         int len=(int)ans.size();
106         printf("Case %d: %d\n", ca, Max-1);
107         for(int i=0; i<len; i++)
108         {
109             printf("%d", ans[i]);
110             if(i==len-1) printf("\n");
111             else printf(" ");
112         }
113 
114     }
115     return 0;
116 }

 

AC通道

HDU 3639 Hawk-and-Chicken

原文地址:https://www.cnblogs.com/zhj5chengfeng/p/2962296.html