强连通分量-tarjan算法缩点

news2024/11/25 4:20:27

 一. 什么是强连通分量?

强连通分量:在有向图G中,如果两个顶点u,v间(u->v)有一条从u到v的有向路径,同时还有一条从v到u的有向路径,则称两个顶点强连通(strongly connected)。如果有向图G的每两个顶点都强连通,称G是一个强连通图。有向图的极大强连通子图,称为强连通分量。
简单点说就是:如果一个有向图中,存在一条回路,所有的结点至少被经过一次,这样的图为强连通图。
在强连图图的基础上加入一些点和路径,使得当前的图不在强连通,称原来的强连通的部分为强连通分量。

二. 强连通分量有什么用途呢?

在图论中,我们可以利用强连通分量进行缩点,从而可以减少很多不必要的操作,降低程序的时间复杂度。

三. tarjan求强连通分量

在讲tarjan算法之前我们先来讲几个概念:
1.树枝边:x是y的父节点,那么x到y的边称为树枝边。
2.前向边:x是y的祖先节点,那么x到y的边称为前向边。
3.后向边:y是x的的祖先节点,那么y到x的边称为后向边。
4.横叉边:x是y的祖先节点,并且y能到达已经搜过的点,那么这条边被称为横叉边。

根据定义可以得知:树枝边也是一个特殊的前向边。
我们在深度优先搜索的时候是从上向下搜的,所以画图看一下(自己画的图,可能有点丑 )
3951ea4ea6d74e628cfd978653bc9484.png#pic_center
知道这些定义后,我们来看一下tarjan算法是如何求强连通分量的。
在这里,我们引入一个时间戳的概念:在深度优先搜索的时候,当前结点x是第几个被搜索到的,记为df[x]。
对于每一个结点,我们定义两个时间戳。
df[x]:x结点是第几个被搜索到的。
low[x]:从x结点开始搜索,能搜索到深度最低的结点是什么,也就是能搜索到时间戳最小的结点。
在搜索的时候我们该如何判断是一个新的强连通分量呢?
如果一个图是强连通的话,那么必然会搜完他图中的所有结点,并且从任意一个结点到达另一个结点,所以强连通分量中的点都可以遍历到时间戳更小的点。
所以我们可以发现,如果一个结点的df[]==low[]的话,那么说明这个结点是不能搜到比自己的时间戳更小的点了。说明什么呢?说明该节点就是一个强连通分量的最高点,也就是一个新的强连通分量。

下面放入一个题(受欢迎的牛):

每一头牛的愿望就是变成一头最受欢迎的牛。

现在有 N 头牛,编号从 1 到 N,给你 M 对整数 (A,B),表示牛 A 认为牛 B 受欢迎。

这种关系是具有传递性的,如果 A 认为 B 受欢迎,B 认为 C 受欢迎,那么牛 A 也认为牛 C 受欢迎。

你的任务是求出有多少头牛被除自己之外的所有牛认为是受欢迎的。

输入格式
第一行两个数 N,M;

接下来 M 行,每行两个数 A,B,意思是 A 认为 B 是受欢迎的(给出的信息有可能重复,即有可能出现多个 A,B)。

输出格式
输出被除自己之外的所有牛认为是受欢迎的牛的数量。

数据范围
1≤N≤10^4,
1≤M≤5×10^4
输入样例:
3 3
1 2
2 1
2 3
输出样例:
1
样例解释
只有第三头牛被除自己之外的所有牛认为是受欢迎的。

这题乍一看是传递闭包,第一时间会想到Floyd,但是看了数据范围之后发现传递闭包会超时,所以Floyd是不可行的。

我们用强连通分量来做。
题意:a->b且b->c,则a->c

要求的是有多少头牛被除自己之外的所有牛认为是受欢迎的(受欢迎的牛可以被其他的牛走到)。

总结:当一个强连通的出度为0,则该强连通分量中的所有点都被其他强连通分量的牛欢迎,但假如存在两及以上个出度=0的牛(强连通分量) 则必然有一头牛(强连通分量)不被所有牛欢迎。

AC代码:

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

const int N=1e4+10,M=5*N;

int h[N],e[M],ne[M],idx;  //邻接表
int id[N];   //id[x]:x结点属于第几个强连通分量
int cnt,times;  //cnt:强连通分量的个数,times:时间戳
int n,m;
bool st[N];  //st[x]:x结点是否在栈中
int df[N],low[N];  //df[x]:x结点第一次被搜索到的时间戳,low[x]:x结点能遍历到最高的点
int sizes[N];  //sizes[x]:第x强连通分量中点的个数
int stack[N],top;  //这里我们用数组模拟栈
int dout[N];  //dout[x]:第x个强连通分量的出度

void add(int a,int b){
    e[idx]=b;
    ne[idx]=h[a];
    h[a]=idx++;
}

void tarjan(int u){
    //当前点的时间戳
    df[u]=low[u]=++times;
    //把u点入栈
    stack[++top]=u;
    st[u]=true;
    //遍历u结点能到的点
    for(int i=h[u];i!=-1;i=ne[i]){
        int j=e[i];
        if(!df[j]){  //如果没有遍历过,那么就遍历它
            tarjan(j);
            low[u]=min(low[u],low[j]);
        }
        else if(st[j]) low[u]=min(low[u],low[j]);  //如果在栈中
    }
    
    //找到一个强连通分量
    if(df[u]==low[u]){
        cnt++;
        int t=stack[top--];
        id[t]=cnt;
        st[t]=false;
        sizes[cnt]++;
        while(t!=u){
            t=stack[top--];
            id[t]=cnt;
            st[t]=false;
            sizes[cnt]++;
        }
    }
}

int main(){
    scanf("%d%d",&n,&m);
    memset(h,-1,sizeof h);
    while(m--){
        int a,b;
        scanf("%d%d",&a,&b);
        add(a,b);
    }
    
    for(int i=1;i<=n;i++){
        if(!df[i]){
            tarjan(i);
        }
    }
    
    for(int i=1;i<=n;i++){
        for(int j=h[i];j!=-1;j=ne[j]){
            int t=e[j];
            int a=id[i],b=id[t];  //a:i结点所在的强连通分量,b:t结点所在的强连通分量
            if(a!=b) dout[a]++;  //因为是a->b,所以a的出度++
        }
    }
    
    int zero=0;  //出度为0点的个数
    int sum=0;
    for(int i=1;i<=cnt;i++){
        if(!dout[i]){
            sum+=sizes[i];
            zero++;
        }
    }
    
    if(zero>1) printf("%d",0);
    else printf("%d",sum);
    
    return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/613264.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Linux - 第24节 - Linux高级IO(二)

1.I/O多路转接之select 1.1.select初识 select是系统提供的一个多路转接接口。 • select系统调用可以让我们的程序同时监视多个文件描述符的上的事件是否就绪。 • select的核心工作就是等&#xff0c;当监视的多个文件描述符中有一个或多个事件就绪时&#xff0c;select才会…

Selenium Python 自动抓取个股数据

Selenium是广泛使用的开源Web UI&#xff08;用户界面&#xff09;自动化测试套件之一。支持Chrome, Edge, Firfox等常见浏览器&#xff0c;Selenium Python库也是python对web应用进行自动化测试的非常有用的工具。 Selenium 还适合用于抓取Javascript 动态网页数据。 本文演…

Spring Bean、XML方式Bean配置、Bean实例化配置、Bean注入

文章目录 Bean管理一、SpringBoot Bean 初了解1.1 了解1.2 Bean的作用域1.2.1 注意事项 1.3 第三方Bean 二、 基于XML方式Bean的配置2.1 SpringBean配置概览2.2 bean id class 配置2.3 bean name 别名配置2.4 bean scope 作用范围2.5 bean 延迟加载2.6 bean 初始化与销毁方法配…

数据结构中的顺序表的实现

文章目录 前言一、初识数据结构二、顺序表的实现&#xff08;类型一&#xff09;1.顺序表的头文件2.顺序表的实现 三、顺序表的实现&#xff08;类型二&#xff09;1 顺序表头文件2 顺序表的实现 四、线性表&#xff08;顺序表&#xff09;的缺点总结 前言 本期就进入到我们数据…

[前端语法]js原型链有关的继承问题

深夜反而思维更活跃一些 (1)js中的原型链 js中存在一个名为原型链的机制,其特点如下 加入一个方法A,A方法一个属性为prototype,这个属性会指向某个对象,也成为A类对象的原型对象. 当我们根据A这个方法生成一个对象a,那么a的原型(proto)属性即为这个对象 a可以调用一些原型…

【cropperjs】优秀、优雅的前端图片裁剪库

下载 npm i cropperjsnpm官网- https://www.npmjs.com/package/cropperjs cropperjs关键参数 aspectRatio 图片裁剪比例 默认值 &#xff1a;NaN作用&#xff1a;图片裁剪比例值&#xff1a;自定义裁剪比例&#xff0c;例如1 / 1 , 4 / 3 , 16 / 9等 viewMode 裁剪模式 默认…

代码随想录算法训练营第二十七天| 39. 组合总和、 40.组合总和II、 131.分割回文串

组合总数 题目链接&#xff1a;力扣 这题和之前题目的区别在于&#xff0c;本题没有数量要求&#xff0c;可以无限重复的取某一元素&#xff0c;但是对元素的总和有限制&#xff0c;这就说明了递归的限制不在于层数&#xff0c;而是选取元素的总和超过target就返回 终止条件为…

【owt】WebrtcNode, subscirbe-sdp offer 流程(2)

流程图 创建MediaStream&#xff0c; MediaStream一方面作为从VideoFramePacketizer接收到媒体数据&#xff1b; 创建VideoFramePacketizer&#xff0c;MediaStream 把sink 注册到VideoFramePacketizer&#xff0c;这样VideoFramePacketizer&#xff08;继承了MediaSource&…

upload靶场通关(12-21关)

Pass-12&#xff08;白名单校验&#xff08;GET 型 0x00 截断&#xff09;&#xff09; 先看提示&#xff1a; 一头雾水&#xff0c;只知道了上传路径是可控的 查看源码&#xff1a; 能看懂就看看&#xff0c;反正我是看了同学的笔记得知这是白名单&#xff0c;按照文件名进行…

Customizable constraint systems for succinct arguments学习笔记(1)

1. 引言 微软研究中心Srinath Setty、a16z crypto research 和 Georgetown University Justin Thaler、Carnegie Mellon University Riad Wahby 20203年论文《Customizable constraint systems for succinct arguments》。 在该论文中&#xff0c;介绍了Customizable constra…

CMake学习(1): CMake基本使用

https://subingwen.cn/cmake/CMake-primer/ 1. CMake 概述 CMake是一个项目构建工具&#xff0c;并且是跨平台的。Cmake跟Makefile其实是差不多的&#xff0c;只不过makefile更底层些。大多是 IDE 软件都集成了 make&#xff0c;比如&#xff1a;VS 的 nmake、linux 下的 GNU…

单链表OJ题:LeetCode--141.环形链表

朋友们、伙计们&#xff0c;我们又见面了&#xff0c;本期来给大家解读一下LeetCode中的第141道单链表OJ题&#xff0c;如果看完之后对你有一定的启发&#xff0c;那么请留下你的三连&#xff0c;祝大家心想事成&#xff01; 数据结构与算法专栏&#xff1a;数据结构与算法 个 …

龙岗区五联土地整备利益统筹项目,集体物业集中签约仪式

五联土地整备利益统筹项目启动以来街道高度重视相关工作开专题会、建工作组、设党支部把征拆工作一项项推进 截至6月1日已完成&#xff1a; 清租签约73户&#xff0c;面积9.55万m&#xff08;意向签约17户&#xff0c;约1.66万m&#xff09; 私人住宅业主补偿安置签约8户&…

Java语言----反射、枚举以及lambda表达式

目录 一.反射 1.1反射的基本情况 1.2反射中最重要的类 1.2.1 Class类 1.2.2Field类 1.2.3Constructor类 1.2.4Methood类 1.3反射优缺点 二.枚举 2.1概念 2.2枚举&#xff08;enum&#xff09;类方法 2.3枚举的构造 三.Lambda表达式 3.1Lambda介绍 3.2 函数式接…

AI实战营:深度学习预训练与MMPreTrain

目录 一、MMPretrain算法库介绍 二、经典主干网络 残差网络ResNet&#xff08;2015&#xff09; Vision Transformer(2020) 三、自监督学习 四、多模态算法 一、MMPretrain算法库介绍 算法库与任务组成&框架概览 预训练工具箱MMPretrain Python推理API 环境搭建 O…

数据结构与算法·第4章【串】

串是有限长的字符序列&#xff0c;由一对单引号相括&#xff0c;如: “a string” 可以理解为c的 s t r i n g string string 基本操作 S t r A s s i g n , S t r C o m p a r e , S t r L e n g t h , C o n c a t , S u b S t r i n g StrAssign,StrCompare,StrLength,Conc…

大数据技术——使用IDEA开发Scala程序

目录 一、使用IDEA开发WordCount程序... 3 二、实验目的... 3 三、实验要求... 3 四、实验环境... 3 五、实验步骤... 3 4.1.1启动IDEA并创建一个新项目WordCount 3 4.1.2为WordCount项目添加Scala框架支持... 7 4.1.3数据准备... 8 4.1.4设置项目目录... 9 4.1.5新建…

webAPI学习笔记4——PC端网页特效

目录 1. 元素偏移量 offset 系列 1.1 offset 概述 1.2 offset 与 style 区别 offset style !!&#xff01;&#xff01;&#xff01;&#xff01;&#xff01;案例&#xff1a;获取鼠标在盒子内的坐标 &#xff01;&#xff01;&#xff01;&#xff01;&#xff01;&…

Jeston Orin Nnao 安装pytorch与torchvision环境

大家好&#xff0c;我是虎哥&#xff0c;Jeston Orin nano 8G模块&#xff0c;提供高达 40 TOPS 的 AI 算力&#xff0c;安装好了Jetpack5.1之后&#xff0c;我们需要配置一些支持环境&#xff0c;来为我们后续的深度学习开发提供支持。本章内容&#xff0c;我将主要围绕安装对…

OCR图片文字识别,人工手动图片标注软件安装过程

OCR图片文字识别&#xff0c;人工手动图片标注软件安装过程&#xff0c;本章关注标注软件的安装&#xff0c;启动过程 1. 下载 anaconda anaconda 下载慢的问题&#xff1a; 使用国内镜像地址下载&#xff1a; https://mirrors.bfsu.edu.cn/anaconda/archive/ https://www.ana…