题意:n个小朋友传递手帕,如果A传递给B B传递给C 那么C会得到A和B的手帕,问你那些小朋友会得到最多种类的手帕(不算自己的手帕)。
思路:对于在同一个强联通分量的小朋友,他们得到的手帕数量是相同的,都为所在联通分量点数减一,我们将其缩点,得到一个DAG,剩下的就是计算出度为零的小朋友会得到多少种手帕,正着找不好找,我们将所有边反向,从终点找所有能遍历到的点,更新最大值即可。
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
#include <queue>
using namespace std;
#define REP( i, a, b ) for( int i = a; i < b; i++ )
#define CLR( a , x ) memset( a , x , sizeof a )
const int maxn = 5000 + 10;
const int maxe = 100000 + 10;
struct Edge{
int v, next;
Edge (int v = 0, int next = 0) : v(v), next(next) {}
};
struct SCC{
int Head[maxn], cntE;
int dfn[maxn], low[maxn], dfs_clock;
int scc[maxn], scc_cnt;
int Stack[maxn], top;
bool ins[maxn];
Edge edge[maxe];
void init(){
top = 0;
cntE = 0;
scc_cnt = 0;
dfs_clock = 0;
CLR(ins, 0);
CLR(dfn, 0);
CLR(Head, -1);
}
void add(int u, int v){
edge[cntE] = Edge(v, Head[u]);
Head[u] = cntE++;
}
void Tarjan(int u){
dfn[u] = low[u] = ++dfs_clock;
Stack[top++] = u;
ins[u] = 1;
for (int i = Head[u] ; ~i ; i = edge[i].next){
int v = edge[i].v;
if (!dfn[v]){
Tarjan (v) ;
low[u] = min(low[u], low[v]) ;
}
else if (ins[v])
low[u] = min (low[u], dfn[v]) ;
}
if (low[u] == dfn[u]){
++scc_cnt;
while ( 1 ){
int v = Stack[--top];
ins[v] = 0;
scc[v] = scc_cnt;
if (v == u)
break;
}
}
}
void find_scc(int n){
REP(i, 0, n) if(!dfn[i]) Tarjan (i) ;
}
}scc;
Edge e[maxe];
int cnte, H[maxn];
int cost[maxn], in[maxn];
int ANS[maxn];
int cur_cost[maxn];
int vis[maxn];
int n, m;
vector<int> ans_scc;
void Init(){
memset(H, -1, sizeof(H));
memset(cost , 0, sizeof(cost));
memset(ANS, 0, sizeof(ANS));
memset(in, 0, sizeof(in));
cnte = 0;
ans_scc.clear();
}
void Add(int u, int v){
e[cnte] = Edge(v, H[u]);
H[u] = cnte++;
}
int cur_sum;
void dfs(int u){
for(int i = H[u]; ~i; i = e[i].next){
int v = e[i].v;
if(!vis[v]){
vis[v] = 1;
cur_sum += cost[v];
dfs(v);
}
}
}
int cas = 0;
void solve(){
scanf("%d%d", &n, &m);
scc.init();
for(int i = 0; i < m; i++){
int u, v;
scanf("%d%d", &u, &v);
scc.add(u, v);
}
scc.find_scc(n);
Init();
for(int i = 0; i < n; i++)
for(int j = scc.Head[i]; ~j; j = scc.edge[j].next){
int u = i, v = scc.edge[j].v;
if(scc.scc[u] != scc.scc[v]){
Add(scc.scc[v], scc.scc[u]);
in[scc.scc[u]]++;
}
}
for(int i = 0; i < n; i++)
cost[scc.scc[i]]++;
int ans = 0;
for(int i = 1; i <= scc.scc_cnt; i++)
if(!in[i]){
cur_sum = cost[i];
memset(vis, 0, sizeof(vis));
dfs(i);
ANS[i] = cur_sum;
ans = max(ans, cur_sum);
}
int f = 0;
printf("Case %d: %d\n", ++cas, ans - 1);
for(int i = 0; i < n; i++){
if(ANS[scc.scc[i]] == ans){
if(f) printf(" "); f = 1;
printf("%d", i);
}
}
printf("\n");
}
int main()
{
//freopen("in.txt", "r", stdin);
int T;
scanf("%d", &T);
while(T--) solve();
return 0;
}