【强连通分量】 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) 指在一个有向图中, ...
随机推荐
- Android如何添加多张引导页
摘要:项目需要添加多张引导页,所以在网上搜集了一些资料并整理好. Step1 添加一个GuideActivity. 其实这个引导页无非就是一个Activity,里面有一个ViewPager而已.多张图 ...
- C#串口扫描枪的简单实现
原文:C#串口扫描枪的简单实现 串口扫描枪的简单实现 基于串口通讯的扫描枪的实现,主要借助SerialPort类,表示串行端口资源.实现很简单: 工具:usb转RS232转接头/个,扫描枪/套, 扫描 ...
- opencv中的仿射变换
什么是仿射变换? 原理:1.一个任意的仿射变换都能表示为 乘以一个矩阵(线性变换) 接着再 加上一个向量(平移) 2.综上所述,我们能够用仿射变换来表示: 1)旋转(线性变换) 2)平移(向量加) 3 ...
- navicat常用快捷键及注意事项
常用快捷键: 1. ctrl + q: 打开新查询窗口 2. ctrl + r: 运行当前窗口内的所有语句 3. ctrl + w: 关闭当前窗口 4. F6: 打开一个mysql命令行窗口 ---- ...
- 启动子Activity
启动普通子Activity: 一个activity启动另一个activity最简单的方式是使用 startActivity(Intent) 方法: public void startActivity( ...
- Three Steps to Migrate Group Policy Between Active Directory Domains or Forests Using PowerShell
Three Steps Ahead Have you ever wished that you had three legs? Imagine how much faster you could ru ...
- [oldboy-django][2深入django]mysql查询语句--原生sql
# 增(一共有三种方式) # 插入单条记录 insert into t1(name,...) values('lzp',..); 注意一点:t1(name,...)必须包含所有非空列(除去自增列) # ...
- android下拉弹出动画
<?xml version="1.0" encoding="utf-8"?> <set xmlns:android="http:// ...
- line-height与vertical-align
css世界读书笔记: 内联元素与流 块级元素负责结构,内联元素接管内容 x元素的下边缘就是我们的基线baseline x-height就是x的高度 vertical-align:middle是x中点位 ...
- POJ 3481 Double Queue(Treap模板题)
Double Queue Time Limit: 1000MS Memory Limit: 65536K Total Submissions: 15786 Accepted: 6998 Des ...