【强连通分量】 Kosaraju和Tarjan算法 (标准模板+详细注释)
题意:求最大强连通分量的大小以及所包含的顶点有哪些
Tarjan算法
#include<iostream>
#include<queue>
#include<list>
#include<vector>
#include<cstring>
#include<set>
#include<stack>
#include<map>
#include<cmath>
#include<algorithm>
#include<string>
#include<stdio.h>
using namespace std;
typedef long long ll;
#define MS(x,i) memset(x,i,sizeof(x))
#define rep(i,s,e) for(int i=s; i<=e; i++)
#define sc(a) scanf("%d",&a)
#define scl(a) scanf("%lld",&a)
#define sc2(a,b) scanf("%d %d", &a, &b)
#define debug printf("debug......\n");
#define pfd(x) printf("%d\n",x)
#define pfl(x) printf("%lld\n",x)
const double eps=1e-8;
const double PI = acos(-1.0);
const int inf = 0x3f3f3f3f;
const ll INF = 0x7fffffff;
const int maxn = 5e3+10;
int dx[4] = {0, 0, 1, -1};
int dy[4] = {1, -1, 0 , 0};
int n,m;//顶点数 边数
vector<int> G[maxn];//存图
int sccCount;//强连通分量的个数
int id;//记录访问次序
bool onStack[maxn];//记录该点是否在栈上
int ids[maxn];//记录该顶点是哪一次被访问到的
int low[maxn];//low值
stack<int> stak;//栈
int color[maxn];//color[i]表示i被涂成的颜色
int sz[maxn];//sz[i]表示强连通分量i的大小
//从一点出发dfs 如果dfs调用完毕后,该结点的id值等于low值 说明得到一个scc
void dfs(int u){
stak.push(u);//入栈
onStack[u] = 1;//标记
ids[u] = low[u] = id++;//记录访问次序 和 low值
for(int i=0; i<G[u].size(); i++){ //遍历所有邻接点
int v = G[u][i];
if(!ids[v]){
dfs(v);//如果没有访问过则继续dfs
low[u] = min(low[u], low[v]);//父节点记录最小的low子结点
}
else if(onStack[v]) low[u] = min(low[u] , dfn[v]);//如果访问过了,并且在栈上
//则回溯更新 栈的作用实际上是使各个SCC互不干涉
}
//如果这个顶点是最早入栈的那个 则SCC已经形成
//认为他能代表这个SCC缩成的点
if(ids[u] == low[u]){
sccCount++;//下一个SCC
while(true){
int tp = stak.top();
stak.pop();
color[tp] = sccCount;
sz[sccCount]++;//size增加
onStack[tp] = 0;//栈标记取消
low[tp] = ids[u];//low值同一更新成u的 不要也行
if(tp == u) break;//到u了不要再弹了
}
}
}
void tarjan(){
id = 0;
sccCount=0;
MS(ids , 0);
MS(sz , 0);
rep(i , 1, n){
if(!ids[i]) dfs(i);
}
int idx;
int maxx = -1;
rep(i,1,n){
if(sz[i] > maxx){
idx = i;
maxx = sz[i];
}
}
cout<<sz[idx]<<endl;
rep(i,1,n){
if(color[i] == idx){
cout<<i<<" ";
}
}
cout<<endl;
}
int main(){
ios::sync_with_stdio(false);
cin>>n>>m;
int u,v,w;
rep(i,1,m){
cin>>u>>v>>w;
G[u].push_back(v);
if(w == 2)
G[v].push_back(u);
}
tarjan();
return 0;
}
- Kosaraju算法
#include<iostream>
#include<queue>
#include<list>
#include<vector>
#include<cstring>
#include<set>
#include<stack>
#include<map>
#include<cmath>
#include<algorithm>
#include<string>
#include<stdio.h>
using namespace std;
typedef long long ll;
#define MS(x,i) memset(x,i,sizeof(x))
#define rep(i,s,e) for(int i=s; i<=e; i++)
#define sc(a) scanf("%d",&a)
#define scl(a) scanf("%lld",&a)
#define sc2(a,b) scanf("%d %d", &a, &b)
#define debug printf("debug......\n");
#define pfd(x) printf("%d\n",x)
#define pfl(x) printf("%lld\n",x)
const double eps=1e-8;
const double PI = acos(-1.0);
const int inf = 0x3f3f3f3f;
const ll INF = 0x7fffffff;
const int maxn = 5e3+10;
int dx[4] = {0, 0, 1, -1};
int dy[4] = {1, -1, 0 , 0};
int n,m;
vector<int> G[maxn];//原图
vector<int> reG[maxn];//逆向图
bool vis[maxn];//访问标记
stack<int> order;//逆向图的逆序访问顺序
int col[maxn];//顶点染色
int cnt;//强连通分量的个数
int sz[maxn];///每个强连通分量的大小
//初始化
void init(){
rep(i,1,n){
G[i].clear();
reG[i].clear();
vis[i] = 0;
col[i] = 0;
sz[i] = 0;
}
while(!order.empty()) order.pop();
cnt = 0;
}
//复用DFS R表示是不是遍历逆向图 如果是 则 不需要染色并且需要入栈 否则需要染色 不需要入栈
void dfs(vector<int> G[] , int s, bool R){
vis[s] = 1;
if(!R){
col[s] = cnt;//把这个顶点染色成cnt
sz[cnt]++;//该颜色连通 分量size++
}
for(int i=0; i< G[s].size(); i++){
int v = G[s][i];
if(!vis[v]) dfs(G,v,R);
}
if(R) order.push(s);//逆序进栈
}
//获取反向图的逆序遍历序列
void getOrder(){
rep(i,1,n){
if(!vis[i]) dfs(reG , i, 1);
}
}
//求强连通分量 按照order序列顺序dfs原图
void getSCC(){
MS(vis , 0);
while(!order.empty()){
int u = order.top();
order.pop();
if(!vis[u]){
cnt++;//产生一个以U为主导的新的强连通分量
dfs(G , u , 0);
}
}
}
//打印结果
void solve(){
int mx = -1, color = 1;
rep(i , 1, n){
if(sz[i] > mx){
mx = sz[i];
color = i;
}
}
cout<<mx<<endl;
rep(i , 1, n){
if(col[i] == color){
cout<<i<<" ";
}
}
cout<<endl;
}
int main(){
int u,v,x;
while(cin>>n>>m){
init();
rep(i,1,m){
cin>>u>>v>>x;
G[u].push_back(v);
reG[v].push_back(u);
if(x==2){
G[v].push_back(u);
reG[u].push_back(v);
}
}
getOrder();
getSCC();
solve();
}
return 0;
}
【强连通分量】 Kosaraju和Tarjan算法 (标准模板+详细注释)的更多相关文章
- 有向图强连通分量的Tarjan算法及模板
[有向图强连通分量] 在有向图G中,如果两个顶点间至少存在一条路径,称两个顶点强联通(strongly connected),如果有向图G的每两个顶点都强联通,称有向图G是一个强联通图.非强联通图有向 ...
- 模板 - 图论 - 强连通分量 - Kosaraju算法
这个算法是自己实现的Kosaraju算法,附带一个缩点,其实缩点这个跟Kosaraju算法没有什么关系,应该其他的强连通分量算法计算出每个点所属的强连通分量之后也可以这样缩点. 算法复杂度: Kosa ...
- 【强联通图 | 强联通分量】HDU 1269 迷宫城堡 【Kosaraju或Tarjan算法】
为了训练小希的方向感,Gardon建立了一座大城堡,里面有N个房间(N<=10000)和M条通道(M<=100000),每个通道都是单向的,就是说若称某通道连通了A房间和B房间,只说明 ...
- Tarjan求强连通分量、求桥和割点模板
Tarjan 求强连通分量模板.参考博客 #include<stdio.h> #include<stack> #include<algorithm> using n ...
- 有向图的强连通分量——kosaraju算法
一.前人种树 博客:Kosaraju算法解析: 求解图的强连通分量
- 模板 - 强连通分量 - Kosaraju
Kosaraju算法 O(n+m) vector<int> s; void dfs1(int u) { vis[u] = true; for (int v : g[u]) if (!vis ...
- 图的强连通分量-Kosaraju算法
输入一个有向图,计算每个节点所在强连通分量的编号,输出强连通分量的个数 #include<iostream> #include<cstring> #include<vec ...
- 强连通分量-----Kosaraju
芝士: 有向图强连通分量在有向图G中,如果两个顶点vi,vj间(vi>vj)有一条从vi到vj的有向路径,同时还有一条从vj到vi的有向路径,则称两个顶点强连通(strongly connect ...
- 强连通分量(Korasaju & Tarjan)学习笔记
好久以前学过的东西...现在已经全忘了 很多图论问题需要用到强连通分量,还是很有必要重新学一遍的 强连通分量(Strongly Connected Component / SCC) 指在一个有向图中, ...
随机推荐
- PAT乙级1088
1088 三人行 (20 分) 子曰:“三人行,必有我师焉.择其善者而从之,其不善者而改之.” 本题给定甲.乙.丙三个人的能力值关系为:甲的能力值确定是 2 位正整数:把甲的能力值的 2 个数字调换位 ...
- Hive UDF开发指南
编写Apache Hive用户自定义函数(UDF)有两个不同的接口,一个非常简单,另一个...就相对复杂点. 如果你的函数读和返回都是基础数据类型(Hadoop&Hive 基本writable ...
- CART树 python小样例
决策树不断将数据切分成小数据集,直到所有目标变量完全相同,或者数据不能再切分为止,决策时是一种贪心算法,它要在给定的时间内做出最佳选择,但并不关心能否达到最优 树回归 优点:可以对复杂和非线性的数据建 ...
- vue-cli 中引入 jq
vue-cli webpack 引入jquery 今天费了一下午的劲,终于在vue-cli 生成的工程中引入了jquery,记录一下.(模板用的webpack) 首先在package.json里的 ...
- leetcode 【 Triangle 】python 实现
题目: Given a triangle, find the minimum path sum from top to bottom. Each step you may move to adjace ...
- 移动web前端开发小结
注意:Chrome模拟手机的显示的界面是有误差的,强烈建议一定要在真机测试自己的移动端页面(以移动端页面为准). 1.页面高度渲染错误,页面的高度是否包含了导航,(华为手机就是偏偏有底部菜单) 设置窗 ...
- [译]tar打包时忽略某些文件夹内容
使用tar的 --exclude的选项 $ tar --exclude='./folder' --exclude='./upload/folder2' -zcvf /backup/filename.t ...
- Zookeeper 增删改查
初始化对象连接到zookeeper服务: public ZooKeeper initZk(){ final CountDownLatch countDownLatch = new CountDownL ...
- 关于caffe 是如何卷积的一点总结
最近,在看caffe源码时,偶然在网上看到一个问题?觉得挺有意思,于是,仔细的查了相关资料,并将总结写在这里,供大家迷惑时,起到一点启示作用吧. 问题的题目是CNN中的一个卷积层输入64个通道的特征子 ...
- vivo和OPPO手机刷机
vivo和OPPO手机是蓝绿两厂,定位年轻时尚女士,比较注重拍照和听音乐,其他无视. 系统很少更新,Root和刷机也比较困难,建议是直接卡刷. 小米手机耍猴(猴子精,代指懂点手机的人) 蓝绿两厂是耍猪 ...