求SCC缩点,统计出每个SCC中的点的个数。

然后统计能到达u的最多的点的个数,可以反向建图,再dfs一遍统计出来。

最后说一下,有必要开一个标记数组,因为测试数据中有重边,结果无限WA。

 #include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
#include <stack>
using namespace std; const int maxn = + ;
int n, m;
vector<int> G[maxn]; stack<int> S;
int pre[maxn], lowlink[maxn], sccno[maxn], sz[maxn], dfs_clock, scc_cnt; void dfs(int u)
{
pre[u] = lowlink[u] = ++dfs_clock;
S.push(u); for(int i = ; i < G[u].size(); i++)
{
int v = G[u][i];
if(!pre[v])
{
dfs(v);
lowlink[u] = min(lowlink[u], lowlink[v]);
}
else if(!sccno[v]) lowlink[u] = min(lowlink[u], pre[v]);
} if(pre[u] == lowlink[u])
{
scc_cnt++;
for(;;)
{
int x = S.top(); S.pop();
sccno[x] = scc_cnt;
sz[scc_cnt]++;
if(x == u) break;
}
}
} void find_scc()
{
dfs_clock = scc_cnt = ;
memset(pre, , sizeof(pre));
memset(sccno, , sizeof(sccno));
memset(sz, , sizeof(sz));
for(int i = ; i < n; i++) if(!pre[i]) dfs(i);
} int support[maxn];
int indeg[maxn];
bool vis[maxn];
vector<int> G2[maxn]; int dfs2(int u)
{
int ans = sz[u];
vis[u] = true;
for(int i = ; i < G2[u].size(); i++)
{
int v = G2[u][i];
if(vis[v]) continue;
ans += dfs2(v);
}
return ans;
} int main()
{
int T; scanf("%d", &T);
for(int kase = ; kase <= T; kase++)
{
scanf("%d%d", &n, &m);
for(int i = ; i < n; i++) G[i].clear();
while(m--)
{
int u, v; scanf("%d%d", &u, &v);
G[u].push_back(v);
} find_scc(); memset(indeg, , sizeof(indeg));
for(int i = ; i <= scc_cnt; i++) G2[i].clear();
for(int i = ; i < n; i++)
for(int j = ; j < G[i].size(); j++)
{
int u = sccno[i], v = sccno[G[i][j]];
if(u == v) continue;
indeg[u]++;
G2[v].push_back(u);
} int ans = ;
for(int i = ; i <= scc_cnt; i++) if(!indeg[i])
{
memset(vis, false, sizeof(vis));
support[i] = dfs2(i);
ans = max(ans, support[i]);
} printf("Case %d: %d\n", kase, ans - );
bool flag = false;
for(int i = ; i < n; i++)
{
int u = sccno[i];
if(!indeg[u] && support[u] == ans)
{
if(flag) printf(" ");
printf("%d", i);
flag = true;
}
}
puts("");
} return ;
}

代码君

05-23 00:13