模板——Tarjan

#include <cstdio>
#include <cstring>
#include <iostream>
#include <vector>
using namespace std;
const int maxn=2000;
vector<int>tu[maxn];
vector<int>lt[maxn];
int n,m,lts=0;
int js=0;
int dfn[maxn],low[maxn];
int zhan[maxn],top=0;
bool isins[maxn];
void tarjan(int i)
{
    int j;
    dfn[i]=low[i]=++js;
    isins[i]=1;
    zhan[top++]=i;
    for(int j=0;j<tu[i].size();j++)
    {
        int tp=tu[i][j];
        if(dfn[tp]==-1)
            tarjan(tp),
            low[i]=min(low[i],low[tp]);
        else if(isins[tp])
            low[i]=min(low[i],dfn[tp]);
    }
    if(dfn[i]==low[i])
    {
        lts++;
        do{
            j=zhan[--top];
            isins[j]=0;
            lt[lts].push_back(j);
        }while(i!=j);
    }
}
void solve(int n)
{
    memset(dfn,-1,sizeof dfn);
    memset(low,-1,sizeof low);
    memset(zhan,-1,sizeof zhan);
    memset(isins,0,sizeof isins);
    for(int i=0;i<n;i++)
        if(dfn[i]==-1)
            tarjan(i);
}
int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=m;i++)
    {
        int x,y;
        scanf("%d%d",&x,&y);
        tu[x].push_back(y);
    }
    solve(n);
    for(int i=1;i<=lts;i++)
    {
        cout<<i<<":";
        for(int j=0;j<lt[i].size();j++)
            cout<<lt[i][j]<<" ";
        cout<<endl;
    }
    return 0;
}
时间: 2024-10-12 03:51:41

模板——Tarjan的相关文章

HDU 1269 强连通模板 Tarjan算法

求强连通量,为1输出Yes否则No Tarjan算法模板 具体讲解:https://www.byvoid.com/zht/blog/scc-tarjan #include "stdio.h" #include "string.h" struct Edge { int v,next; }edge[100010]; int head[10010],stack[10010],dfn[10010],low[10010]; // stack栈: dfn深搜次序数组:low结点

算法模板——Tarjan强连通分量

功能:输入一个N个点,M条单向边的有向图,求出此图全部的强连通分量 原理:tarjan算法(百度百科传送门),大致思想是时间戳与最近可追溯点 这个玩意不仅仅是求强连通分量那么简单,而且对于一个有环的有向图可以有效的进行缩点(每个强连通分量缩成一个点),构成一个新的拓扑图(如BZOJ上Apio2009的那个ATM)(PS:注意考虑有些图中不能通过任意一个单独的点到达全部节点,所以不要以为直接tarjan(1)就了事了,还要来个for循环,不过实际上复杂度还是O(M),因为遍历过程中事实上每个边还是

【连通图】双连通模板 Tarjan

比起求无向图关节点的算法,只是多了一个栈,用来储存不存在关节点的所有边,遇到关节点之后弹出所有边进行储存 int dfs(int u, int fa) { int lowu = dfn[u] = ++deep; int son = 0; for(int i = head[u]; ~i; i = e[i].next) { int v = e[i].v; Pair p = Pair(u, v); if(!dfn[v]) { s.push(p); son++; int lowv = dfs(v, u)

【强连通】强连通模板 Tarjan

比起双连通的Tarjan我倒是觉得反而简单多了.思想和双连通分量是同一个模式. #include <cstdio> #include <cstring> #include <cstdlib> #include <stack> using namespace std; const int N = 1e5; int dfn[N], scc_id[N]; int deep, scc_cnt; stack <int> s; int dfs(int u)

[模板]tarjan缩点+拓扑排序

题目:给定一个n个点m条边有向图,每个点有一个权值,求一条路径,使路径经过的点权值之和最大.你只需要求出这个权值和. 允许多次经过一条边或者一个点,但是,重复经过的点,权值只计算一次. 题目简述:先tarjan缩点,再从入度为零处进行一次拓扑排序,求最长路即可,话说拓扑排序求最长路真方便... 注意: 要明确拓扑的写法,要用栈写最优. 1 #include<bits/stdc++.h> 2 using namespace std; 3 #define man 100010 4 inline i

【关节点+桥】关节点和桥模板 Tarjan

#include <cstdio> #include <cstring> #include <algorithm> using namespace std; const int N = 1e5, M = 1e5; struct Edge { int v, next, idx; Edge(){} Edge(int _v, int _next, int _idx): v(_v), next(_next), idx(_idx){} }e[M]; int dfn[N], dee

[模板] tarjan/联通分量/dfs树

边的分类 有向图边分为四类: 树边, 前向边, 返祖边(后向边), 横叉边. 上图: 判定 有向图 对图进行dfs, 不考虑已经遍历过的点, 得到dfs序 \(dfn_i\). 在dfs过程中, 记录当前dfs栈. 对于边\((u,v)\), 树边: \(vis_v==0\); 前向边: \(vis_v==1\) 且 \(dfn_v > dfn_u\); 返祖边: \(vis_v==1\) 且 \(dfn_v < dfn_u\), 且 \(v\) 在当前栈内; 横叉边: \(vis_v==1\

tarjan算法模板

var {left表示点 root 没离开栈 vis表示点 root 有没有被访问过} i,n,m,now,time,color,top:longint; v:array[0..10001] of record start:longint;end; e:array[0..100001] of record y,next:longint;end; dfn,low,stack,encolor:array[0..10001] of longint; vis,left:array[0..10001] o

【模板】割点(割顶)(洛谷_3388)——tarjan

tarjan求割点,打了个模板题. #include<iostream> #include<cstdio> #include<vector> using namespace std; inline int read(){ int t=1,num=0;char c=getchar(); while(c>'9'||c<'0'){if(c=='-')t=-1;c=getchar();} while(c>='0'&&c<='9'){num