Kosaraju两次深搜实现强连通分量

Kosaraju两次深搜实现强连通分量

kosaraju算法进行两次dfs,第一次在原图上进行,并在结点递归调用返回时将结点压入一个栈中,第二次dfs在原图的逆图上进行,并且初始点选择栈中最上面的点,每次dfs所访问的点构成一个强连通分量。

第一次看kosaraju算法的时候,我很不解,为什么第二次dfs随便遍历一下就能找到一个强连通分量呢?后来才顿悟,这里关键是选取的遍历起始点的顺序。这里就要好好研究一下为什么第一次遍历能够为第二次遍历打下这么神奇的基础。其实第一次dfs的操作,非常像一个基础的算法——拓补排序,对,操作基本是一样的,只是这里的目的不是得到每个结点的拓补有序序列,而是。。。。对,其实不难想到,是强连通分量的拓补有序序列


#include<iostream>
#include<memory.h>
using namespace std;
int n,m;
int tis,tit,tst;
int g[5000][5000];
int d[50000];
int ge[50000];
int vis[50000];
int t=0;
void dfs1(int v0)
{
    vis[v0]=1;
    for(int i=1;i<=n;i++)
    if(!vis[i]&&g[v0][i])dfs1(i);
    d[++t]=v0;
}//top序
void dfs2(int v0)
{
    vis[v0]=t;//v0属于第t个强连通分量
    ge[t]++;
    for(int i=1;i<=n;i++)
    if(!vis[i]&&g[i][v0])dfs2(i);
}
int main()
{
    kosaraju:
    cin>>n>>m;
    for(int i=1;i<=m;i++)
    {
        cin>>tis>>tit>>tst;
        g[tis][tit]=tst;
        if(tst==2)g[tit][tis]=tst;
    }
    for(int i=1;i<=n;i++)if(!vis[i])dfs1(i);
    memset(vis,0,sizeof(vis));
    t=0;
    for(int i=n;i>=1;i--)if(!vis[d[i]])t++,dfs2(d[i]);
    int maxx=-0x7fffffff/2;
    int p;
    for(int i=1;i<=t+1;i++)
    {
        if(maxx<ge[i])
        maxx=ge[i],p=i;
    }
    cout<<maxx<<endl;
    for(int i=1;i<=n;i++)
    {
        if(vis[i]==p)
        cout<<i<<" ";
    }
}

摘自CSDN

原文地址:https://www.cnblogs.com/boruto/p/9559615.html

时间: 2024-07-31 03:04:56

Kosaraju两次深搜实现强连通分量的相关文章

Kosaraju算法解析: 求解图的强连通分量

1. 定义 连通分量:在无向图中,即为连通子图. 上图中,总共有四个连通分量.顶点A.B.C.D构成了一个连通分量,顶点E构成了一个连通分量,顶点F,G和H,I分别构成了两个连通分量. 强连通分量:有向图中,尽可能多的若干顶点组成的子图中,这些顶点都是相互可到达的,则这些顶点成为一个强连通分量. 上图中有三个强连通分量,分别是a.b.e以及f.g和c.d.h. 2. 连通分量的求解方法 对于一个无向图的连通分量,从连通分量的任意一个顶点开始,进行一次DFS,一定能遍历这个连通分量的所有顶点.所以

[图论] 有向图强连通分量 (kosaraju算法,Tarjan算法)

记录自己的想法:在有向图中,如果一些顶点中任意两个顶点都能互相到达(间接或直接),那么这些顶点就构成了一个强连通分量,如果一个顶点没有出度,即它不能到达其他任何顶点,那么该顶点自己就是一个强连通分量.在用kosaraju算法和Tarjan算法求强连通分量的时候,就是给所有的顶点分组染色,同一种颜色的顶点在同一个强连通分量中,记录有多少种颜色(有多少个强联通分量),每个顶点属于哪种颜色(每个顶点在哪个强连通分量重).在同一个强连通分量中的所有顶点可以缩为一个顶点,然后根据缩点构造DAG(有向无环图

第四关——图论:强连通分量

14:27:28 写一首十几岁听的情歌,可惜我没在那个时候遇见你,否则我努力活到百岁以后,就刚好爱你一整个世纪  ——<零几年听的情歌> 今天是待在学校的最后一天了,撒花,庆祝!!!那也祝自己十六岁生日快乐 最近肺炎传染有点严重,大家能点外卖点外卖,能躺床躺床,少出门,你肆无忌惮赖在家的机会来了!!! 好了,今天要讲的呢,是要待在家好好学习一下的强连通分量. 概念 连通分量:在无向图中,即为连通子图. 有向图强连通分量:在有向图G中,如果两个顶点vi,vj间(vi>vj)有一条从vi到v

图之强连通、强连通图、强连通分量 Tarjan算法

强连通分量 简介 在阅读下列内容之前,请务必了解图论基础部分. 强连通的定义是:有向图 G 强连通是指,G 中任意两个结点连通. 强连通分量(Strongly Connected Components,SCC)的定义是:极大的强连通子图. 这里想要介绍的是如何来求强连通分量. Tarjan 算法 Robert E. Tarjan (1948~) 美国人. Tarjan 发明了很多算法结构.光 Tarjan 算法就有很多,比如求各种联通分量的 Tarjan 算法,求 LCA(Lowest Comm

DFS-BFS(深搜广搜)原理及C++代码实现

深搜和广搜是图很多算法的基础,很多图的算法都是从这两个算法中启发而来. 深搜简单地说就是直接一搜到底,然后再回溯,再一搜到底,一直如此循环到没有新的结点. 广搜简单地说就是一层一层的搜,像水的波纹一样往外面扩散,扩散到最外层搜索也就完成了. prim最小生成树.Dijkstra单源最短路径算法都使用了类似广度优先搜索的思想. 拓扑排序就可以用深搜来实现,分解强连通分量也可以用深搜来实现(转置图加两次深搜) 我们实现广搜时需要用队列来辅助我们进行.实现深搜时使用栈来辅助我们进行,所以显而易见的用递

UVA - 11324 The Largest Clique (DAG + 强连通分量)

题目大意:给出一张有向图G,求一个结点数最大的结点集,使得该点集中任意两个结点u和v满足: 要么u可到达v,要么v可以到达u(u和v互相可达也可以) 解题思路:u和v相互可达的时候,就是两个结点在同一个强连通分量内的时候 首先要保证集合里面的点可达:强连通分量就满足集合内的点都相互可达.所以第一件事就是找出所有的强连通分量,并统计出每个强连通分量内的结点数 然后找出每个强连通分量之间的关系,也就是找出两个强连通分量之间的桥,连接可连接的强连通分量 最后将每个强连通分量收缩,得到SCC图.此时的S

POJ2186 Popular Cows 【强连通分量】+【Kosaraju】+【Tarjan】+【Garbow】

Popular Cows Time Limit: 2000MS   Memory Limit: 65536K Total Submissions: 23445   Accepted: 9605 Description Every cow's dream is to become the most popular cow in the herd. In a herd of N (1 <= N <= 10,000) cows, you are given up to M (1 <= M &l

POJ2186 Popular Cows 【强连通分量Kosaraju】

Popular Cows Time Limit: 2000MS   Memory Limit: 65536K Total Submissions: 23445   Accepted: 9605 Description Every cow's dream is to become the most popular cow in the herd. In a herd of N (1 <= N <= 10,000) cows, you are given up to M (1 <= M &l

强连通分量-----Kosaraju

芝士: 有向图强连通分量在有向图G中,如果两个顶点vi,vj间(vi>vj)有一条从vi到vj的有向路径,同时还有一条从vj到vi的有向路径,则称两个顶点强连通(strongly connected).如果有向图G的每两个顶点都强连通,称G是一个强连通图.有向图的极大强连通子图,称为强连通分量. 如图中1,2,3,4是一个强连通分量. Kosaraju算法: 如果这是一个无向图,那么从一个节点出发,深搜得到的所有节点都是连通的. 但这是一个有向图,起始节点的不同会导致结果的不同,举个栗子,从5搜