首先建图时多建一个反向边的图。
vector<int> G[MAXN], rG[MAXN];
算法的核心就是跑两遍 dfs:
第一遍 dfs 求出从一个点开始遍历图回溯时所得到的后序序列(必须是后序,试过不是后序就会错。至于为什么,能力不足实在是研究了好久没研究出来,而且网上的博客也只是讲了要求后序而没有讲为什么)。
第二遍对反向边生成的图 dfs ,从记录的后序序列的最后一个点开始 dfs ,需要 dfs 几次,那么就有几个强连通分量且每次 dfs 能够到达的点一定在一个强连通分量中。
而对于这道题来说,只需要在每次记录强连通分量中点的个数然后取最大的把该分量中的点输出即可。
代码:
#include <cstdio>
#include <cmath>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <iostream>
#include <string>
#include <queue>
#include <stack>
#include <vector>
#include <map>
#include <set>
#include <bitset>
using namespace std;
typedef long long ll;
#define int ll
#define INF 0x3f3f3f3f3f3f3f3f
#define MAXM 100000 + 10
#define MAXN 5000 + 10
const ll mod = 1e9 + 7;
#define P pair<int, int>
#define fir first
#define sec second
int n, m;
vector<int> G[MAXN], rG[MAXN];
int post[MAXN], vis[MAXN], cnt;
int ct[MAXN], ctt, num[MAXN];
void dfs(int now)
{
for(int i = 0; i < G[now].size(); i ++) {
if(!vis[G[now][i]]) {
vis[G[now][i]] = 1;
dfs(G[now][i]);
}
}
post[cnt++] = now;
}
void rdfs(int now)
{
for(int i = 0; i < rG[now].size(); i ++) {
if(!vis[rG[now][i]]) {
vis[rG[now][i]] = 1;
ct[ctt] ++;
num[rG[now][i]] = ctt;
rdfs(rG[now][i]);
}
}
}
signed main()
{
cin >> n >> m;
for(int i = 0; i < m; i ++) {
int a, b, x; cin >> a >> b >> x;
G[a].push_back(b);
rG[b].push_back(a);
if(x == 2) {
G[b].push_back(a);
rG[a].push_back(b);
}
}
for(int i = 1; i <= n; i ++) {
if(!vis[i]) {
vis[i] = 1;
dfs(i);
}
}
memset(vis, 0, sizeof(vis));
int ma = 0, ans;
for(int i = cnt - 1; i >= 0; i --) {
if(!vis[post[i]]) {
vis[post[i]] = 1;
ct[++ctt] = 1;
num[post[i]] = ctt;
rdfs(post[i]);
if(ct[ctt] > ma) {
ma = ct[ctt];
ans = ctt;
}
}
}
cout << ma << endl;
for(int i = 1; i <= n; i ++) {
if(num[i] == ans) {
cout << i << (--ma == 0 ? '\n' : ' ');
}
}
}
/*
The WAM is F**KING interesting .
*/