题意:
大学班级选班长,N 个同学均可以发表意见 若意见为 A B 则表示 A 认为 B 合适,意见具有传递性,即 A 认为 B 合适,B 认为 C 合适,则 A 也认为 C 合适 勤劳的 TT 收集了M条意见,想要知道最高票数,并给出一份候选人名单,即所有得票最多的同学,你能帮帮他吗?
Input
本题有多组数据。
第一行 T 表示数据组数。
每组数据开始有两个整数 N 和 M (2 <= n <= 5000, 0 <m <= 30000),
接下来有 M 行包含两个整数 A 和 B(A != B) 表示 A 认为 B 合适。
Output
对于每组数据,第一行输出 “Case x: ”,x 表示数据的编号,从1开始,紧跟着是最高的票数。
接下来一行输出得票最多的同学的编号,用空格隔开,不忽略行末空格!
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
My Solution:
SCC(Strong Connected Component)(极大强连通子图)
Kosaraju 算法: 学习链接
1.深度优先遍历G,算出每个结点u的结束时间f[u],起点如何选择无所谓。
2.深度优先遍历G的转置图G T ,选择遍历的起点时,按照结点的结束时间从大到小进行。遍历的过程中,一边遍历,一边给结点做分类标记,每找到一个新的起点,分类标记值就加1。
3. 第2步中产生的标记值相同的结点构成深度优先森林中的一棵树,也即一个强连通分量
缩点:
将属于同一个强连通分量的点合并,将同一个SCC的点合并成一个点,遍历反图中的每个点的边,如果边的两端不在同一SCC中则加入该边,最终形成新的缩点后的图。
Code:
1 #include<iostream>
2 #include<vector>
3 #include<queue>
4 #include<cstdio>
5 #include<cstring>
6 #include<functional>
7 using namespace std;
8 const int maxn = 30010;
9 int num,m,n,cnt,scnt,st,ta;
10 int ord[maxn],rord[maxn];
11 int scc[maxn],dsc[maxn],indeg[maxn],ans[maxn];
12 bool vis1[maxn],vis2[maxn],vis[maxn];
13 vector<int> G1[maxn],G2[maxn],G3[maxn];
14 void init() {
15 cnt = st = 0;
16 memset(vis,0,sizeof(vis));
17 memset(vis1,0,sizeof(vis1));
18 memset(vis2,0,sizeof(vis2));
19 memset(indeg,0,sizeof(indeg));
20 memset(scc,0,sizeof(scc));
21 memset(dsc,0,sizeof(dsc));
22 memset(ord,0,sizeof(ord));
23 memset(rord,0,sizeof(rord));
24 memset(ans,0,sizeof(ans));
25 for(int i=0; i<=n; i++) {
26 G1[i].clear();
27 G2[i].clear();
28 G3[i].clear();
29 }
30 }
31 void dfs1(int s) {
32 vis1[s] = true;
33 for(vector<int>::iterator i= G1[s].begin(); i!=G1[s].end(); i++) {
34 int d = *i;
35 if(!vis1[d]) {
36 dfs1(d);
37 }
38 }
39 cnt++;
40 ord[s] = cnt;
41 rord[cnt] = s;
42 }
43 void dfs2(int s) {
44 vis2[s] = true;
45 dsc[s] = st;
46 for(vector<int>::iterator i= G2[s].begin(); i!=G2[s].end(); i++) {
47 int d = *i;
48 if(!vis2[d]) {
49 scnt++;
50 dfs2(d);
51 }
52 }
53 }
54 void dfs3(int s) {
55 vis[s] = true;
56 ta += scc[s];
57 for(vector<int>::iterator i= G3[s].begin(); i!=G3[s].end(); i++) {
58 int d = *i;
59 if(!vis[d]) {
60 dfs3(d);
61 }
62 }
63 }
64 int main() {
65 cin>>num;
66 int cn = 0;
67 while(num--) {
68 cn ++;
69 cin>>n>>m;
70 int a,b;
71 init();
72 for(int i=0; i<m; i++) {
73 scanf("%d%d",&a,&b);
74 G1[a+1].push_back(b+1);
75 G2[b+1].push_back(a+1);
76 }
77 for(int i=1; i<=n; i++) {
78 if(!vis1[i]) dfs1(i);
79 }
80 for(int i=n; i>=1; i--) {
81 if(!vis2[rord[i]]) {
82 scnt = 1;
83 st++;
84 dfs2(rord[i]);
85 scc[st] = scnt;
86 }
87 }
88 for(int s=1; s<=n; s++) {
89 for(vector<int>::iterator i= G2[s].begin(); i!=G2[s].end(); i++) {
90 int d = *i;
91 if(dsc[s]!=dsc[d]) {
92 int u = dsc[s],v = dsc[d];
93 indeg[v]++;
94 G3[u].push_back(v);
95 }
96 }
97 }
98 for(int i=1; i<=st; i++) {
99 if(indeg[i]==0) {
100 ta = 0;
101 memset(vis,0,sizeof(vis));
102 dfs3(i);
103 ans[i] = ta - 1;
104 }
105 }
106 int MaxAns = 0;
107 queue<int> ansq;
108 for(int i=1; i<=st; i++) {
109 MaxAns = max(MaxAns,ans[i]);
110 }
111 // cout<<endl;
112 for(int i=1; i<=st; i++) {
113 if(MaxAns==ans[i]) {
114 ansq.push(i);
115 }
116 }
117 priority_queue<int,vector<int>,greater<int> > output;
118 while(ansq.size()) {
119 int tmp = ansq.front();
120 ansq.pop();
121 for(int i=1; i<=n; i++) {
122 if(dsc[i]==tmp) output.push(i-1);
123 }
124 }
125 printf("Case %d: %d\n",cn,MaxAns);
126 while(output.size()>1){
127 printf("%d ",output.top());
128 output.pop();
129 }
130 printf("%d\n",output.top());
131 output.pop();
132 }
133 return 0;
134 }