有向图的强联通分量-SCC-Tarjan算法

有向图的强联通分量(SCC)Tarjan算法

强连通分量(Strongly Connected Components,SCC)的定义是:极大的强连通子图。
下图中,子图{1,2,3,4}为一个强连通分量,因为顶点1,2,3,4两两可达。{5},{6}也分别是两个强连通分量。
image.png

DFS生成树:

image-20230725134818030

  1. 树边(tree edge):示意图中以黑色边表示,每次搜索找到一个还没有访问过的结点的时候就形成了一条树边。
  2. 反祖边(back edge):示意图中以红色边表示(即7->1 ),也被叫做回边,即指向祖先结点的边。
  3. 横叉边(cross edge):示意图中以蓝色边表示(即9->7 ),它主要是在搜索的时候遇到了一个已经访问过的结点,但是这个结点 并不是 当前结点的祖先。
  4. 前向边(forward edge):示意图中以绿色边表示(即3->6 ),它是在搜索的时候遇到子树中的结点的时候形成的。

image-20230725131614577

image.png

默写tarjan算法梳理的思路:

  1. 加时间戳;
  2. 放入栈中,做好标记;
  3. 遍历邻点:
    1. 如果没遍历过,tarjan一遍,用low[j]更新最小值low;
    2. 如果在栈中,用dfn[j]更新最小值low
  4. 找到最高点:
    1. scc个数++
    2. do-while循环:从栈中取出每个元素;标志为出栈;对元素做好属于哪个scc;该scc中点的数量+ +
vector<int> e[N]; 
int dfn[N],low[N],tot;
int stk[N],instk[N],top;
int scc[N],siz[N],cnt;

void tarjan(int x){
  //入x时,盖戳、入栈
  dfn[x]=low[x]=++tot;
  stk[++top]=x,instk[x]=1;
  for(int y : e[x]){
    if(!dfn[y]){//若y尚未访问
      tarjan(y);
      low[x]=min(low[x],low[y]);//回x时更新low
    }
    else if(instk[y])//若y已访问且在栈中
      low[x]=min(low[x],dfn[y]);//在x时更新low
  }
  //离x时,收集SCC
  if(dfn[x]==low[x]){//若x是SCC的根
    int y; ++cnt;
    do{
      y=stk[top--];
      instk[y]=0;
      scc[y]=cnt;//SCC编号
      ++siz[cnt];//SCC大小
    }while(y!=x);
  }
}

[USACO06JAN] The Cow Prom S

https://www.luogu.com.cn/problem/P2863

题目描述

有一个 n n n 个点, m m m 条边的有向图,请求出这个图点数大于 1 1 1 的强连通分量个数。

输入格式

第一行为两个整数 n n n m m m

第二行至 m + 1 m+1 m+1 行,每一行有两个整数 a a a b b b,表示有一条从 a a a b b b 的有向边。

输出格式

仅一行,表示点数大于 1 1 1 的强连通分量个数。

样例 #1

样例输入 #1

5 4
2 4
3 5
1 2
4 1

样例输出 #1

1

提示

数据规模与约定

对于全部的测试点,保证 2 ≤ n ≤ 1 0 4 2\le n \le 10^4 2n104 2 ≤ m ≤ 5 × 1 0 4 2\le m\le 5\times 10^4 2m5×104 1 ≤ a , b ≤ n 1 \leq a, b \leq n 1a,bn

思路

tarjan求强联通分量,感觉使用vector记录强联通分量比较好,可以知道每个强联通分量里面有哪些点,也可以知道大小。

代码

/**
 * https://www.luogu.com.cn/problem/P2863
 */
#include <bits/stdc++.h>

#define int long long
using namespace std;

const int N = 1e4 + 10;
vector<int> e[N];
int dfn[N], low[N], total, cnt;
stack<int> stk;
bool instk[N];
vector<int> scc[N];

void tarjan(int x) {
    dfn[x] = low[x] = ++total;
    stk.push(x), instk[x] = true;
    for (auto y: e[x]) {
        if (!dfn[y]) {
            tarjan(y);
            low[x] = min(low[x], low[y]);
        } else if (instk[y]) {
            low[x] = min(low[x], dfn[y]);
        }
    }
    if (dfn[x] == low[x]) {
        int y;
        cnt++;
        do {
            y = stk.top();
            stk.pop();
            instk[y] = false;
            scc[cnt].push_back(y);
        } while (y != x);
    }
}

signed main() {
#ifndef ONLINE_JUDGE
    freopen("test.in", "r", stdin);
    freopen("test.out", "w", stdout);
#endif
    int n, m;
    cin >> n >> m;
    for (int i = 0; i < m; ++i) {
        int x, y;
        cin >> x >> y;
        e[x].push_back(y);
    }
    for (int i = 1; i <= n; i++) {
        if (!dfn[i]) {
            tarjan(i);
        }
    }
    int res = 0;
    for (int i = 1; i <= cnt; i++) {
        if (scc[i].size() > 1)
            res++;
    }
    cout << res << endl;

    return 0;
}

Checkposts

https://www.luogu.com.cn/problem/CF427C

题面翻译

题目描述
你的城市有N个路口。路口之间有一条单程道路。作为城市的市长,你必须确保所有路口的安全。

为了确保安全,你必须建造一些警察检查站。一个检查站只能建在一个路口。 如果有一个检查站在i路口,保护j的条件是:i==j或者警察巡逻车可以从i走到j,并且能回到i。

建造检查站要花一些钱。 由于城市的某些地区比其他地区更昂贵,在某些路口修建检查站可能比其他路口花费更多的钱。

你必须确定以确保所有路口的安全所需的最低资金。

此外,你必须找到以的最低价格和在最小数量的检查站确保安全的方案数。

如果其中任何一个路口包含其中一个检查点而不包含在另一个路口中,则两种方式是不同的。

答案模 1000000007(10^9+7)1000000007(10
9
+7)
输入输出格式
输入格式:
n (路口数)

n个数 (每个路口建检查站的花费)

m (以下m行是m条有向道路)

x y (一条从x到y的有向道路)

输出格式:
一行用空格分割的两个数:

最小花费 方案数

题目描述

Your city has $ n $ junctions. There are $ m $ one-way roads between the junctions. As a mayor of the city, you have to ensure the security of all the junctions.

To ensure the security, you have to build some police checkposts. Checkposts can only be built in a junction. A checkpost at junction $ i $ can protect junction $ j $ if either $ i=j $ or the police patrol car can go to $ j $ from $ i $ and then come back to $ i $ .

Building checkposts costs some money. As some areas of the city are more expensive than others, building checkpost at some junctions might cost more money than other junctions.

You have to determine the minimum possible money needed to ensure the security of all the junctions. Also you have to find the number of ways to ensure the security in minimum price and in addition in minimum number of checkposts. Two ways are different if any of the junctions contains a checkpost in one of them and do not contain in the other.

输入格式

In the first line, you will be given an integer $ n $ , number of junctions $ (1<=n<=10^{5}) $ . In the next line, $ n $ space-separated integers will be given. The $ i^{th} $ integer is the cost of building checkpost at the $ i^{th} $ junction (costs will be non-negative and will not exceed $ 10^{9} $ ).

The next line will contain an integer $ m (0<=m<=3·10^{5}) $ . And each of the next $ m $ lines contains two integers $ u_{i} $ and $ v_{i} (1<=u_{i},v_{i}<=n; u≠v) $ . A pair $ u_{i},v_{i} $ means, that there is a one-way road which goes from $ u_{i} $ to $ v_{i} $ . There will not be more than one road between two nodes in the same direction.

输出格式

Print two integers separated by spaces. The first one is the minimum possible money needed to ensure the security of all the junctions. And the second one is the number of ways you can ensure the security modulo $ 1000000007 $ $ (10^{9}+7) $ .

样例 #1

样例输入 #1

3
1 2 3
3
1 2
2 3
3 2

样例输出 #1

3 1

样例 #2

样例输入 #2

5
2 8 0 6 0
6
1 4
1 3
2 4
3 4
4 5
5 1

样例输出 #2

8 2

样例 #3

样例输入 #3

10
1 3 2 2 1 3 1 4 10 10
12
1 2
2 3
3 1
3 4
4 5
5 6
5 7
6 4
7 3
8 9
9 10
10 9

样例输出 #3

15 6

样例 #4

样例输入 #4

2
7 91
2
1 2
2 1

样例输出 #4

7 1

思路

利用tarjan算法求SCC进行缩点,然后对于每个点内,可以使用map来求这个点内的最小代价以及出现的次数,,每个点内必须要选一个最小代价即可,总方案数就是利用乘法原理,把每个点内最小代价出现的次数乘起来即可。

代码

#include <bits/stdc++.h>

#define int long long
using namespace std;

const int N = 1e5 + 10, mod = 1e9 + 7;
vector<int> e[N], scc[N];
int dfn[N], low[N], st[N], cnt, total;//total是时间戳,cnt是SCC长度
stack<int> q;
int n, m;
int w[N];

void tarjan(int x) {
    dfn[x] = low[x] = ++total;
    q.push(x), st[x] = true;
    for (auto y: e[x]) {
        if (!dfn[y])tarjan(y), low[x] = min(low[x], low[y]);
        else if (st[y]) low[x] = min(low[x], dfn[y]);
    }
    if (dfn[x] == low[x]) {
        int y;
        ++cnt;
        do {
            y = q.top();
            q.pop();
            st[y] = false;
            scc[cnt].push_back(y);
        } while (y != x);
    }
}

signed main() {
#ifndef ONLINE_JUDGE
    freopen("../test.in", "r", stdin);
    freopen("../test.out", "w", stdout);
#endif
    cin >> n;
    for (int i = 1; i <= n; ++i) {
        cin >> w[i];
    }
    cin >> m;
    for (int i = 1; i <= m; ++i) {
        int x, y;
        cin >> x >> y;
        e[x].push_back(y);
    }
    for (int i = 1; i <= n; ++i) {
        if (!dfn[i]) tarjan(i);
    }
    vector<map<int, int>> cost(cnt + 1);
    int mi = 0, res = 1;
    for (int i = 1; i <= cnt; ++i) {
        for (auto x: scc[i]) {
            cost[i][w[x]]++;
        }
        for (auto [x, y]: cost[i]) {
            mi += x;
            res = (res * y) % mod;
            break;
        }
    }
    cout << mi << " " << res << endl;

    return 0;
}

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

c语言练手项目【编写天天酷跑游戏2.0】EASYX图形库的运用。代码开源,素材已打包

天天酷跑项目的开发 项目前言 项目是基于Windows&#xff0c;easyX图形库进行开发的&#xff0c; 开发环境&#xff1a;Visual Studio 2022 项目技术最低要求&#xff1a; 常量&#xff0c;变量&#xff0c;数组&#xff0c;循环&#xff0c;函数。 文章目录 天天酷跑项目的…

Hadoop概念学习(无spring集成)

Hadoop 分布式的文件存储系统 三个核心组件 但是现在已经发展到很多组件的s 或者这个图 官网地址: https://hadoop.apache.org 历史 hadoop历史可以看这个: https://zhuanlan.zhihu.com/p/54994736 优点 高可靠性&#xff1a; Hadoop 底层维护多个数据副本&#xff0c;所…

初识网络 --- 浅了解一些基础概念

文章目录 初识网络局域网与广域网 初识协议协议分层 OSI七层模型TCP/IP 四层&#xff08;五层&#xff09;模型网络传输基本流程协议报头局域网通信原理传输流程图数据包封装和分用 初识网络 在每台计算机独立的情况下&#xff1a;假设现在有三台计算机&#xff0c;每台计算机…

2024考研408-操作系统 第五章-输入输出IO管理 学习笔记

文章目录 一、I/O管理概述1.1、I/O设备的概念与分类1.1.1、什么是I/O设备&#xff1f;1.1.2、I/O设备的分类&#xff1a;按照使用特性1.1.2、I/O设备的分类&#xff1a;按传输速率分类1.1.3、I/O设备的分类&#xff1a;按照信息交换的单位分类知识点回顾与重要考点 1.2、I/O控制…

SpringBoot Redis 使用Lettuce和Jedis配置哨兵模式

Redis 从入门到精通【应用篇】之SpringBoot Redis 配置哨兵模式 Lettuce 和Jedis 文章目录 Redis 从入门到精通【应用篇】之SpringBoot Redis 配置哨兵模式 Lettuce 和Jedis前言Lettuce和Jedis区别1. 连接方式2. 线程安全性 教程如下1. Lettuce 方式配置1.1. 添加 Redis 和 Let…

【目标跟踪】1、基础知识

文章目录 一、卡尔曼滤波二、匈牙利匹配 一、卡尔曼滤波 什么是卡尔曼滤波&#xff1f;——状态估计器 卡尔曼滤波用于在包含不确定信息的系统中做出预测&#xff0c;对系统下一步要做什么进行推测&#xff0c;且会结合推测值和观测值来得到修正后的最优值卡尔曼滤波就是利用…

git 和adb

一、git 1、git的作用 git是一个版本控制系统&#xff0c;是一种记录一个或若干文件内容变化&#xff0c;以便将来查阅特定版本修订情况的系统。 我的理解就是代码管理器&#xff1a; 第一点你可将代码备份到git仓上&#xff1b; 第二点可记录的你修改记录&#xff1b; 第三点…

周训龙老兵参观广西森林安全紧急救援装备演练

7月21日上午&#xff0c;周训龙老兵参观广西紧急救援促进中心在南宁市青秀山举行森林安全紧急救援装备演练&#xff0c;多功能水罐消防车、无人救援机等先进设备轮番上阵&#xff0c;展示了广西应对突发事件的紧急救援速度和水平。广西壮族自治区应急厅不情愿参此次演练活动。 …

Python Flask构建微信小程序订餐系统 (十)

🔥 编辑会员信息 🔥 编辑会员信息可以通过点击会员列表操作,也可以点击会员信息详情点击进行操作 🔥 修改编程会员信息列表布局 🔥 修改 web/templates/member/index.html 文件,添加跳转到编辑会员信息的页面 web/templates/member/set.html 🔥 创建用于会员…

Mybatis单元测试,不使用spring

平时开发过程中需要对mybatis的Mapper类做单元测试&#xff0c;主要是验证语法是否正确&#xff0c;尤其是一些复杂的动态sql&#xff0c;一般项目都集成了spring或springboot&#xff0c;当项比较大时&#xff0c;每次单元测试启动相当慢&#xff0c;可能需要好几分钟&#xf…

OpenCV图像处理-图像分割-MeanShift

MeanShift 1. 基本概念2.代码示例 1. 基本概念 MeanShift严格说来并不是用来对图像进行分割的&#xff0c;而是在色彩层面的平滑滤波。它会中和色彩分布相近的颜色&#xff0c;平滑色彩细节&#xff0c;侵蚀掉面积较小的的颜色区域&#xff0c;它以图像上任意一点P为圆心&…

优思学院|六西格玛案例分析 - 降低焊接缺陷率

大家都知道六西格玛方法中的控制图有助于监测流程的稳定性和识别特有原因的发生。对流程周期性地采样&#xff0c;当测量结果在控制上限和下限内&#xff0c;而且围绕着一条中心线时&#xff0c;我们就说流程是受控的。注意上述控制上限和下限有别于规范限。 我们来看看一家工…

电脑安装双系统ubuntu18.04+windows后开机直接进入Windows解决方法

电脑型号&#xff1a;联想拯救者Y9000K2021H 系统&#xff1a;Windows11Ubuntu18.04双系统 问题&#xff1a;笔记本安装双系统后&#xff0c;Windows系统下处理word或者看论文&#xff1b;Ubuntu18.04系统安装ros进行机械臂控制等的研究。但最近开机后发现没有系统选项了&#…

知识库数据导出为excel-使用JavaScript实现在浏览器中导出Excel文件

我们智能客服知识库机器人已经开发完成&#xff0c;后端数据库是使用的qdrant向量数据库&#xff0c;但是该数据库并没有导出备份功能&#xff0c;所以我按简单的纯前端实现知识库导出excel数据 使用第三方库(如SheetJS) SheetJS是一个流行的JavaScript库&#xff0c;可帮助处理…

App隐私及合规评估服务

随着移动应用种类和数量呈爆发式增长&#xff0c;APP侵害用户权益事件层出不穷&#xff0c;为规范个人信息的收集使用&#xff0c;打击涉及个人信息违法犯罪行为&#xff0c;我国相继出台多个涉及个人信息保护相关法律法规。与此同时&#xff0c;中央网信办、工信部、公安部、市…

获取大疆无人机的飞控记录数据并绘制曲线

机型M350RTK&#xff0c;其飞行记录文件为加密的&#xff0c;我的完善代码如下 gitgithub.com:huashu996/DJFlightRecordParsing2TXT.git 一、下载安装官方的DJIFlightRecord git clone gitgithub.com:dji-sdk/FlightRecordParsingLib.git飞行记录文件在打开【我的电脑】&am…

Istio Pilot源码学习(二):ServiceController服务发现

本文基于Istio 1.18.0版本进行源码学习 4、服务发现&#xff1a;ServiceController ServiceController是服务发现的核心模块&#xff0c;主要功能是监听底层平台的服务注册中心&#xff0c;将平台服务模型转换成Istio服务模型并缓存&#xff1b;同时根据服务的变化&#xff0c…

OpenHarmony与HarmonyOS联系与区别

目录 1. 背景 2.OpenHarmony 3.HarmonyOS 4.鸿蒙生态 5.OpenHarmony与HarmonyOS的技术上实现区别 1.语言支持 2.SDK 的不同 3.运行调测方式不同 4.对APK的兼容性不同 5.包含关系 6.调试命令 6.何时选择OpenHarmony或是HarmonyOS&#xff1f; 1. 背景 开篇就说“关于…

2023最新谷粒商城笔记之Sentinel概述篇(全文总共13万字,超详细)

Sentinel概述 服务流控、熔断和降级 什么是熔断 当扇出链路的某个微服务不可用或者响应时间太长时&#xff0c;会进行服务的降级&#xff0c;**进而熔断该节点微服务的调用&#xff0c;快速返回错误的响应信息。**检测到该节点微服务调用响应正常后恢复调用链路。A服务调用B服…

Spring Security 身份验证的基本类/架构

目录 1、SecurityContextHolder 核心类 2、SecurityContext 接口 3、Authentication 用户认证信息接口 4、GrantedAuthority 拥有权限接口 5、AuthenticationManager 身份认证管理器接口 6、ProviderManager 身份认证管理器的实现 7、AuthenticationProvider 特定类型的…