题目大意
有 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 人数最多的点,输出组成这些点的人即可
参考代码

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 }