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

news2024/11/24 7:54:42

有向图的强联通分量(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;
}

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

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

相关文章

B2B2C多商户跨境电商购物网站搭建(后台采集功能)

如何部署开发一个B2B2C开源多语言多商户跨境外贸网站 随着全球化的发展&#xff0c;跨境外贸成为了许多企业拓展业务的重要方向。搭建一个B2B2C跨境外贸网站&#xff0c;将有助于实现企业的全球化经营。那么如何搭建一个B2B2C跨境外贸网站呢&#xff1f; 一、选择合适的开源平…

安科瑞智能照明控制系统的应用发展需求-安科瑞黄安南

【摘 要】 &#xff1a;随着电力电子技术的快速发展&#xff0c;智能照明控制技术已经成为楼宇自动化控制系统的重要组成部分&#xff0c;是绿色照明的发展方向。智能照明控制系统在照明节能上起到重要的作用。文章结合实际案例&#xff0c;探讨了智能照明控制技术在照明节能上…

OK3588的NPU加速推理resnet18—rknn_toolkit_lite2的Python语言篇

OK3588的NPU加速推理MobileNet——Python语言篇 Rknn_toolkit_lite2Miniconda安装创建虚拟环境并运行NPU加速推理代码注释 Rknn_toolkit_lite2 RKNN Toolkit Lite2 主要用于 RKNN 模型在 Rockchip NPU 上的部署。 在使用 RKNN Toolkit Lite2 之前&#xff0c;用户需要先通过 R…

LeetCode:面试题:消失的数字——时间复杂度

题目&#xff1a;数组nums中包含0~n的所有整数&#xff0c;但其中缺失了一个数&#xff0c;请写代码找出那个缺失的整数&#xff0c;要求在时间复杂度为O&#xff08;N&#xff09;的时间内完成 思路1&#xff1a;冒泡排序遍历&#xff08;下一个数不等于上一个数1&#xff0c…

Mybatis中 #{} 和 ${} 的区别,SLQ注入

#{}:预编译处理&#xff0c;类似于占位符。${}:字符直接替换 预编译处理&#xff1a;Mybatis在处理#{}时候&#xff0c;会将SQL中的#{}转换为&#xff1f;&#xff0c;使⽤ PreparedStatement 的 set ⽅法来赋值。 直接替换&#xff1a;是MyBatis 在处理 ${} 时&#xff0c;就是…

浏览器调试Android App

浏览器调试Android App 1. 背景2. 调试工具3. 手机设置4. 打开浏览器(edge)5. 连接手机6. 点击inspect 开始调试 1. 背景 在工作中经常会遇到在原生app中嵌套h5&#xff0c; 但是在某些需要在app里面调试的内容&#xff0c; 却没有像chrome开发者工具这样的工具来帮助我们快速…

PDF文件转换成word软件有哪些?分享两个文件格式转换软件

在日常办公中&#xff0c;我们经常使用各种办公软件&#xff0c;其中PDF和Word是最常见的两种格式。相较于Word文件&#xff0c;PDF文件具有更强的兼容性和安全性&#xff0c;因此我们通常会选择以PDF格式分享文件。然而&#xff0c;如果我们需要提取PDF文件中的部分内容&#…

VPP编译安装及测试

参考&#xff1a;FD.io VPP环境下运行用户应用程序教程 环境 操作系统&#xff1a;centos7.4&#xff0c;且需要联网VPP版本&#xff1a;2009网卡&#xff1a;10G VPP编译 使用git clone VPP项目指定分支的代码&#xff08;注意&#xff1a;不要使用VPP的release版本包&…

设计模式-职责链模式在Java中使用示例-采购审批系统

场景 采购单分级审批 采购审批是分级进行的&#xff0c;即根据采购金额的不同由不同层次的主管人员来审批&#xff0c;主任可以审批5万元以下&#xff08;不包括5万元&#xff09; 的采购单&#xff0c;副董事长可以审批5万元至10万元&#xff08;不包括10万元&#xff09;的…

基于C语言的哈夫曼转化软件

完整资料进入【数字空间】查看——baidu搜索"writebug" 该软件可实现如下功能&#xff1a; 用户可以通过点击“打开文件”按钮打开本地计算机中任意一个文本文件&#xff0c;点击确认将其文本导入到程序输入文本框中&#xff0c;也可以直接在文本框中通过键盘键入文…

502 Bad GateWay报错的解决方法

什么是502 bad gateway 报错 简单来说 502 是报错类型代码 bad gateway 错误的网关。是Web服务器作为网关或代理服务器时收到无效的响应。 用我们的口语说就是运行网站的服务器暂时挂了(不响应)。 产生错误的原因 1.连接超时 我们向服务器发送请求 由于服务器当前链接太多&am…

js设置一个定时器,定时发送请求

1.setTimeout方式 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>Document</title> </he…

整流电路设计

一、交直流电区别 交流电&#xff1a;一般指大小和方向都随时间作周期性变化的电压或电流。交流电的极性在一个周期内变换多次&#xff0c;而直流电则保持恒定。 直流电&#xff08;电压或电流&#xff09;&#xff1a;直流电的方向不随时间而变化。直流电通常又分为恒定电压…

【Linux命令200例】chmod设置文件或目录的访问权限

&#x1f3c6;作者简介&#xff0c;黑夜开发者&#xff0c;全栈领域新星创作者✌&#xff0c;2023年6月csdn上海赛道top4。 &#x1f3c6;本文已收录于专栏&#xff1a;Linux命令大全。 &#x1f3c6;本专栏我们会通过具体的系统的命令讲解加上鲜活的实操案例对各个命令进行深入…

Python获取接口数据

首先我们需要下载python&#xff0c;我下载的是官方最新的版本 3.8.3 其次我们需要一个运行Python的环境&#xff0c;我用的是pychram&#xff0c;需要库的话我们可以直接在setting里面安装 代码&#xff1a; # -*- codeing utf-8 -*- from bs4 import BeautifulSoup # 网页…

Stable Diffusion生成艺术二维码

Stable Diffusion生成艺术二维码 文章会有浏览问题&#xff0c;点击此处查看原文 首先需要一个Stable Diffusion服务环境&#xff0c;《Stable Diffusion服务环境搭建&#xff08;远程服务版&#xff09;》如果你已经有了那就忽略 一、准备一个比较好的二维码底图 首先解析二…

第一章 介绍 对 HL7 版本 2 的支持

文章目录 第一章 介绍InterSystems 对 HL7 版本 2 的支持HL7 版本 2 路由生成 第一章 介绍 InterSystems 对 HL7 版本 2 的支持 InterSystems 产品支持 HL7 版本 2 消息作为虚拟文档。虚拟文档是 InterSystems 产品仅部分解析的一种消息。这种消息具有标准的production 消息头…

微信朋友圈推广优势有哪些?

你知道的朋友圈推广效果有哪些 1、定向精准触达 在朋友圈广告推广中&#xff0c;人群的性别、年龄、兴趣爱好、活动范围、学历、手机型号、推广时段等&#xff0c;这些都是可以进行精准定向。通过精准定向&#xff0c;可以找到企业想找到的人群。 2、用户高活跃度 大家平均每…

亿发数字化生产工厂MES管理系统,助力云南工厂实现智能制造

近年来&#xff0c;云南省将制造业数字化作为“工业强省”战略的关键和打造现代产业体系的重中之重&#xff0c;而随着工业4.0时代的来临&#xff0c;数字化转型已成为制造企业企业蓬勃发展之路。在这个过程中&#xff0c;MES精益制造管理系统显露出潜力&#xff0c;成为云南省…

前端生成批量二维码,并且下载到本地

Ⅰ- 壹 - 功能展示和使用需求 需求描述 前端生成批量二维码&#xff0c;并且下载&#xff0c;本项目使用了 vue3. 功能展示 Ⅱ - 贰 - 封装代码 需要的库 yanr add qrcodejs2-fix // 生成二维码 yarn add html2canvas // 转图片 yarn add jszip// 压缩包 yarn add file-sa…