上篇文章,记录了用Kosaraju算法写这道模板题,为了学习强连通分量,又去学习下Tarjan算法。先看书,嗯,感觉看文字看完了,讲的啥玩意,为啥呀?不懂。于是还是先百度一下吧。啊,这篇文章不错,讲了一些,还给了模板,虽然背后的原理还是没懂,但大致算法步骤知道了。
自己加了很多注释。
/*
*looooop
* Do not go gentle into that good night
* -Dylan Thomas
*/
#include <iostream>
#include <stdio.h>
#include <string.h>
#include <stack>
#include <queue>
#include <map>
#include <set>
#include <vector>
#include <math.h>
#include <bitset>
#include <algorithm>
#include <climits>
using namespace std;
#define lson 2*i
#define rson 2*i+1
#define LS l,mid,lson
#define RS mid+1,r,rson
#define UP(i,x,y) for(i=x;i<=y;i++)
#define DOWN(i,x,y) for(i=x;i>=y;i--)
#define MEM(a,x) memset(a,x,sizeof(a))
#define W(a) while(a)
#define gcd(a,b) __gcd(a,b)
#define LL long long
#define N 1000005
#define MOD 1000000007
#define INF 0x3f3f3f3f
#define EXP 1e-8
#define lowbit(x) (x&-x)
#define MAX 50005
vector<int>G[MAX];
int dfn[MAX]; //Tarjan算法的核心数组,dfn[v]表示顶点被访问的时间
int low[MAX]; //low[v]是与顶点v邻接的未删除的顶点u的low[u]和low[v]的最小值(low[v]初始化为dfn[v])
int belong[MAX]; //表示顶点染色集合,belong[i]表示i的颜色,即i所属的强连通分量
int sum[MAX]; //染色数的集合,sum[i]表示第i种颜色的顶点数量,即连通分量所包含的顶点数量
int vis[MAX];
int cnt;
int tot; //染色数,强连通分量的数量
int n,m;
int a,b,t;
stack<int>ST; //Tarjan所维护dfn,low使用的栈
void Tarjan(int st){
dfn[st] = low[st] = ++tot; //初始化dfn,low
vis[st] = 1; //vis = 1表示在栈中
ST.push(st);
for(int i=0; i < G[st].size(); i++){ //遍历所有相连的边
int v = G[st][i];
if(!dfn[v]){ //还未访问
Tarjan(v);
low[st] = min(low[st],low[v]);
}
else if(vis[v]){ //被访问,但还在栈中
low[st] = min(low[st],dfn[v]);
}
}
if(low[st] == dfn[st]){ //dfn == low表示找到了一个强连通分量子树的根
int x;
++cnt; //染色的色彩,
while(1){ //从连通树中一个个的取分量
x = ST.top();
ST.pop();
vis[x] = 0;
belong[x] = cnt;
sum[cnt]++;
if(x == st) break;
}
}
}
void Solve(){
tot = 0;
cnt = 0;
MEM(dfn,0);
MEM(low,0);
MEM(vis,0);
while(!ST.empty()) ST.pop();
for(int i=1; i <=n; i++){
if(dfn[i] == 0) Tarjan(i);
}
}
int main(int argc,char *argv[]){
scanf("%d%d",&n,&m);
for(int i = 0; i < m; i++){
scanf("%d%d%d",&a,&b,&t);
if(t==1){
G[a].push_back(b);
}
else{
G[a].push_back(b);
G[b].push_back(a);
}
}
Solve();
int temp = 1;
for(int i = 1; i <= tot; i++){
if(sum[i] >= sum[temp]) temp = i;
}
printf("%d\n",sum[temp]);
for(int i = 1; i <= n; i++){
if(belong[i] == temp)
printf("%d ",i);
}
printf("\n");
return 0;
}