【学习整理】Tarjan:强连通分量+割点+割边

Tarjan求强连通分量

在一个有向图中,如果某两点间都有互相到达的路径,那么称中两个点强联通,如果任意两点都强联通,那么称这个图为强联通图;一个有向图的极大强联通子图称为强联通分量

  算法可以在 的时间内求出一个图的所有强联通分量。

表示进入结点 的时间

表示从 所能追溯到的栈中点的最早时间

如果某个点 已经在栈中则更新 

否则对 进行回溯,并在回溯后更新 

#include<iostream>
#include<cstdlib>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<stack>
using namespace std;

int n,m,tot,ind,ans;
int dfn[200005],low[200005],last[200005];
bool ins[200005];
stack<int> s;
struct hh
{
    int fr,to,next;
}e[500005];
void add(int fr,int to)
{
    e[++tot].to=to;e[tot].fr=fr;
    e[tot].next=last[fr];
    last[fr]=tot;
}
void tarjan(int now)
{
    int i,j;
    s.push(now);
    ins[now]=true;
    low[now]=dfn[now]=++dex;
    for(i=last[now];i;i=e[i].next)
        if(!dfn[e[i].to])
        {
            tarjan(e[i].to);
            low[now]=min(low[now],low[e[i].to]);
        }
        else if(ins[e[i].to])low[now]=min(low[now],dfn[e[i].to]);

    if(dfn[now]==low[now])
    {
        cnt=0;
        do
        {
            j=s.top();s.pop();
            ins[j]=false;
            cnt++;
        }while(j!=now);
        ans=max(ans,cnt);
    }
}
int main()
{
    int i,j,u,v;
    scanf("%d%d",&n,&m);
    for(i=1;i<=m;i++)
    {
        scanf("%d%d",&u,&v);
        add(u,v);
    }
    for(i=1;i<=n;i++)
        if(!dfn[i]) tarjan(i);
    printf("%d",ans);
    return 0;
}

Tarjan求割点

在一个无向图中,如果删掉点 后图的连通块数量增加,则称点 为图的割点

对于搜索树上的非根结点 ,如果存在子节点 满足   ,即 向上无法达到 的祖先,则 为割点。

对于搜索树上的根节点,若它的子节点数 ,则 为割点。

void tarjan(int x,int fa)
{
    int i,j;
    dfn[x]=low[x]=++dex;
    for(i=last[x];i;i=e[i].next)
    {
        ++t[x];
        if(!dfn[e[i].to])
        {
            tarjan(e[i].to,x);
            low[x]=min(low[x],low[e[i].to]);
            if(x==root&&t[x]>=2) opt[x]=true;
            else if(x!=root&&low[e[i].to]>=dfn[x]) opt[x]=true;
        }
        else if(e[i].to!=fa) low[x]=min(low[x],dfn[e[i].to]);
    }
}

Tarjan求割边

对于当前结点 ,若邻接点中存在结点 满足 ,则 为割边。

void tarjan(int x,int fa)
{
    int i,j;
    low[x]=dfn[x]=++dex;
    for(i=last[x];i;i=e[i].next)
        if(e[i].to!=fa)
        {
            if(dfn[e[i].to]) low[x]=min(low[x],dfn[e[i].to]);
            else
            {
                tarjan(e[i].to,x);
                low[x]=min(low[x],low[e[i].to]);
                if(low[e[i].to]>dfn[x]) opt[e[i].id]=true;
            }
        }
}
时间: 2024-10-25 10:05:26

【学习整理】Tarjan:强连通分量+割点+割边的相关文章

tarjan[强连通分量][求割边割点][缩点]

强连通分量: 1 #include <bits/stdc++.h> 2 using namespace std; 3 4 const int maxn=100000+15; 5 struct Edge { 6 int x,y,next; 7 Edge(int x=0,int y=0,int next=0): 8 x(x),y(y),next(next) {} 9 } edge[maxn]; 10 int sumedge,head[maxn]; 11 int n,m; 12 int ins(in

小结:双连通分量 &amp; 强连通分量 &amp; 割点 &amp; 割边

概要: 各种dfs时间戳..全是tarjan(或加上他的小伙伴)无限膜拜tarjan orzzzzzzzzz 技巧及注意: 强连通分量是有向图,双连通分量是无向图. 强连通分量找环时的决策和双连通的决策十分相似,但不完全相同. 强连通分量在if(FF[v])后边的else if还要特判是否在栈里,即vis[v],然后才更新LL[u] 割点和强连通分量因为是无向图所以要判个fa,可以在dfs时维护个fa参数 割点如果要求分割的分量,那么就是这个节点对他的子树是割点的数目+1. 割点不需要栈维护但是

hdu1269 Tarjan强连通分量 模板(转)

#include<stdio.h> #include<iostream> #include<vector> using namespace std; const int maxn=10010; vector<int>g[maxn]; int Bcnt; int Top; int Index; int low[maxn],dfn[maxn]; int belong[maxn],stack[maxn]; int instack[maxn]; void Init_

tarjan 强连通分量

一.强连通分量定义 有向图强连通分量在有向图G中,如果两个顶点vi,vj间(vi>vj)有一条从vi到vj的有向路径,同时还有一条从vj到vi的有向路径,则称两个顶点强连通(stronglyconnected).如果有向图G的每两个顶点都强连通,称G是一个强连通图.有向图的极大强连通子图,称为强连通分量(stronglyconnectedcomponents)SCC. 以上是摘自百科的一段对有向图强连通图分量的形式化定义.其实不难理解,举个例子 如上图,{a,b,c,d}为一个强连通分量,{e}

tarjan——强连通分量+缩点

tarjan陪伴强联通分量 生成树完成后思路才闪光 欧拉跑过的七桥古塘 让你 心驰神往"----<膜你抄>   自从听完这首歌,我就对tarjan开始心驰神往了,不过由于之前水平不足,一直没有时间学习.这两天好不容易学会了,写篇博客,也算记录一下.   一.tarjan求强连通分量 1.什么是强连通分量? 引用来自度娘的一句话: "有向图强连通分量:在有向图G中,如果两个顶点vi,vj间(vi>vj)有一条从vi到vj的有向路径,同时还有一条从vj到vi的有向路径,则

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

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

POJ1236 (Network of Schools,Tarjan,强连通分量)

转载自:http://www.tuicool.com/articles/EnMFFja 原创:kuangbin 题意:  一个有向图,求: 1) 至少要选几个顶点,才能做到从这些顶点出发,可以到达全部顶点 2) 至少要加多少条边,才能使得从任何一个顶点出发,都能到达全部顶点,即成为一个强连通分量 思路: 求完强连通分量后,缩点,计算每个点的入度,出度. 第一问的答案就是入度为零的点的个数, 第二问就是max(n,m)  入度为零的个数为n, 出度为零的个数为m 思路详解: 1. 求出所有强连通分

Tarjan——强连通分量

是的你没有看错,又是Tarjan(说过他发明了很多算法),那么什么是Tarjan 首先看看度娘的解释: 有向图强连通分量:在有向图G中,如果两个顶点vi,vj间(vi>vj)有一条从vi到vj的有向路径,同时还有一条从vj到vi的有向路径,则称两个顶点强连通(strongly connected).如果有向图G的每两个顶点都强连通,称G是一个强连通图.有向图的极大强连通子图,称为强连通分量(strongly connected components). 是不是没有看懂,我也是 首先了解几个概念:

Tarjan算法与割点割边

目录 Tarjan算法与无向图的连通性 1:基础概念 2:Tarjan判断割点 3:Tarjan判断割边 Tarjan算法与无向图的连通性 1:基础概念 在说Tarjan算法求解无向图的连通性之前,先来说几个概念: <1. 时间戳:在图的深度优先遍历中,按照每一个结点第一次被访问到的时间顺序,依次给予N个结点1~N的整数边集,该标记就被计位"时间戳",计做 \(dfn[x]\). <2. 搜索树:任选一个结点深度优先遍历,每个点只访问一次.产生递归的边构成的树为搜索树. &