题意:有 n 个人,m 组支持关系,已知支持关系可以传递,比如 A 支持 B,则所有支持 A 的人也同时支持 B,问哪些人获得的支持数最多,最多获得多少支持(自己不能获得自己的支持)。
首先,如果一些人他们互相支持,那么他们的支持数肯定都是一样的,所有支持他们其中一个人的也同时支持他们所有人,所以对于这些人我们可以强连通缩点。然后就获得了一个有向无环图,每个强连通分量有各自的人数。由于支持的人数可以传递,所以某个人支持了别人,那么他获得的支持数就一定不如他支持的人多,那么其实我们需要获得的就只是那些没有支持过别人的人,所以我们可以通过反向建图,那些没有支持别人的人就是入度为 0 的点,从每个这样的点开始DFS下去统计一共有多少个人是他能够到达的,然后再加上他自己的人数 - 1(不能获得自己的支持),这样我们再从中找出最大值以及这些人就行了。
1 #include<stdio.h>
2 #include<string.h>
3 #include<stack>
4 #include<queue>
5 using namespace std;
6
7 const int maxn=5005;
8 const int maxm=30005;
9
10 int head[2][maxn],point[2][maxm],nxt[2][maxm],size[2];
11 int n,t,scccnt,maxx;
12 int stx[maxn],low[maxn],scc[maxn];
13 int dp[maxn],id[maxn],vis[maxn];
14 stack<int>S;
15
16 int max(int a,int b){return a>b?a:b;}
17
18 void init(){
19 memset(head,-1,sizeof(head));
20 size[0]=size[1]=0;
21 memset(dp,0,sizeof(dp));
22 memset(id,0,sizeof(id));
23 maxx=0;
24 }
25
26 void add(int a,int b,int c=0){
27 if(c){
28 for(int i=head[1][a];~i;i=nxt[1][i])if(point[1][i]==b)return;
29 }
30 point[c][size[c]]=b;
31 nxt[c][size[c]]=head[c][a];
32 head[c][a]=size[c]++;
33 }
34
35 void dfs(int s){
36 stx[s]=low[s]=++t;
37 S.push(s);
38 for(int i=head[0][s];~i;i=nxt[0][i]){
39 int j=point[0][i];
40 if(!stx[j]){
41 dfs(j);
42 low[s]=min(low[s],low[j]);
43 }
44 else if(!scc[j]){
45 low[s]=min(low[s],stx[j]);
46 }
47 }
48 if(low[s]==stx[s]){
49 scccnt++;
50 while(1){
51 int u=S.top();S.pop();
52 scc[u]=scccnt;
53 dp[scccnt]++;
54 if(s==u)break;
55 }
56 }
57 }
58
59 void setscc(){
60 memset(stx,0,sizeof(stx));
61 memset(scc,0,sizeof(scc));
62 t=scccnt=0;
63 for(int i=0;i<n;++i)if(!stx[i])dfs(i);
64 for(int i=0;i<n;++i){
65 for(int j=head[0][i];~j;j=nxt[0][j]){
66 int k=point[0][j];
67 if(scc[i]!=scc[k]){
68 add(scc[i],scc[k],1);
69 id[scc[k]]++;
70 }
71 }
72 }
73 }
74
75 int Dp(int s){
76 int ans=0;
77 vis[s]=1;
78 for(int i=head[1][s];~i;i=nxt[1][i]){
79 if(!vis[point[1][i]])ans+=Dp(point[1][i]);
80 }
81 return ans+dp[s];
82 }
83
84 int main(){
85 int T;
86 scanf("%d",&T);
87 for(int q=1;q<=T;q++){
88 int m;
89 scanf("%d%d",&n,&m);
90 init();
91 while(m--){
92 int a,b;
93 scanf("%d%d",&a,&b);
94 add(b,a);
95 }
96 setscc();
97 for(int i=1;i<=scccnt;++i)if(!id[i]){
98 memset(vis,0,sizeof(vis));
99 dp[i]=Dp(i)-1;
100 if(dp[i]>maxx)maxx=dp[i];
101 }
102 int ans=0;
103 printf("Case %d: %d
",q,maxx);
104 int cnt=0;
105 for(int i=0;i<n;++i){
106 if(!id[scc[i]]&&dp[scc[i]]==maxx){
107 if(cnt++)printf(" ");
108 printf("%d",i);
109 }
110 }
111 printf("
");
112 }
113 return 0;
114 }