每周题解:最大半连通子图

news2024/12/23 22:33:34

题目链接

最大半连通子图

题目描述

一个有向图 G = ( V , E ) G=\left(V,E\right) G=(V,E) 称为半连通的 (Semi-Connected),如果满足: ∀ u , v ∈ V \forall u,v\in V u,vV,满足 u → v u\to v uv v → u v\to u vu,即对于图中任意两点 u , v u,v u,v,存在一条 u u u v v v 的有向路径或者从 v v v u u u 的有向路径。

G ′ = ( V ′ , E ′ ) G'=\left(V',E'\right) G=(V,E) 满足 V ′ ⊆ V V'\subseteq V VV E ′ E' E E E E 中所有跟 V ′ V' V 有关的边,则称 G ′ G' G G G G 的一个导出子图。若 G ′ G' G G G G 的导出子图,且 G ′ G' G 半连通,则称 G ′ G' G G G G 的半连通子图。若 G ′ G' G G G G 所有半连通子图中包含节点数最多的,则称 G ′ G' G G G G 的最大半连通子图。

给定一个有向图 G G G,请求出 G G G 的最大半连通子图拥有的节点数 K K K,以及不同的最大半连通子图的数目 C C C。由于 C C C 可能比较大,仅要求输出 C C C X X X 的余数。

输入格式

第一行包含两个整数 N , M , X N,M,X N,M,X N , M N,M N,M分别表示图 G G G 的点数与边数, X X X 的意义如上文所述。

接下来 M M M 行,每行两个正整数 a , b a,b a,b,表示一条有向边 ( a , b ) \left(a,b\right) (a,b)。图中的每个点将编号为 1 , 2 , 3 … N 1,2,3\dots N 1,2,3N,保证输入中同一个 ( a , b ) \left(a,b\right) (a,b)不会出现两次。

输出格式

应包含两行,第一行包含一个整数 K K K,第二行包含整数 C   m o d   X C\bmod X CmodX

样例 #1

样例输入 #1

6 6 20070603
1 2
2 1
1 3
2 4
5 6
6 4

样例输出 #1

3
3

提示

对于 100 % 100\% 100% 的数据, N ≤ 1 0 5 N\le 10^5 N105 M ≤ 1 0 6 M\le 10^6 M106 X ≤ 1 0 8 X\le 10^8 X108

算法思想

根据题目描述,要求出 G G G最大半连通子图拥有的节点数 K K K,以及不同的最大半连通子图的数目 C C C
测试样例如下图所示,图中最大半连通子图有 { 1 , 2 , 4 } \{1,2,4\} {1,2,4} { 2 , 1 , 3 } \{2,1,3\} {2,1,3} { 5 , 6 , 4 } \{5,6,4\} {5,6,4},都拥有 3 3 3个节点。
在这里插入图片描述
由于图中可能存在环,不方便直接求解。考虑先求强连通分量,然后进行缩点得到DAG(有向无环图),在拓扑序列中使用动态规划的思想求图中的最长链,以及最长链的个数。关于强连通分量,可以参考博主的另一篇文章——每周算法:强连通分量。

算法实现

  • 首先用Tarjan算法求强连通分量,然后缩点得到DAG
  • 在拓扑序列中使用动态规划的思想:
    • 定义状态 f [ u ] f[u] f[u]表示以 u u u为终点的最长链的长度,状态 g [ u ] g[u] g[u]表示以 u u u为终点的最长链的个数
    • 若存在一条边 u → v u\to v uv的:
      • 如果 f [ v ] < f [ u ] + s c c _ s i z e [ v ] f[v] < f[u]+ scc\_size[v] f[v]<f[u]+scc_size[v] f [ v ] = f [ u ] + s c c _ s i z e [ v ] , g [ v ] = g [ u ] f[v] = f[u] + scc\_size[v], g[v] = g[u] f[v]=f[u]+scc_size[v],g[v]=g[u],其中 s c c _ s i z e [ v ] scc\_size[v] scc_size[v]表示 v v v所在强连通分量中点的个数。
      • 否则如果 f [ v ] = f [ u ] + s c c _ s i z e [ v ] f[v] = f[u]+ scc\_size[v] f[v]=f[u]+scc_size[v] g [ v ] = g [ v ] + g [ u ] g[v] = g[v] + g[u] g[v]=g[v]+g[u]
  • 最终打擂台求最长链的长度,已经该长度的方案数

代码实现

#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
//由于缩点后还要添加边,因此边数×2
const int N = 1e5 + 5, M = 2e6 + 5; 
int h[N], hd[N], e[M], ne[M], idx; //hd存储DAG的邻接表
int n, m, mod;
int dfn[N], low[N], timestamp, stk[N], top, scc_cnt, id[N], scc_size[N];
bool in_stk[N];
int f[N], g[N];
void add(int h[], int a, int b)  // 在邻接表h中添加一条边a->b
{
    e[idx] = b, ne[idx] = h[a], h[a] = idx ++ ;
}
void tarjan(int u)
{
    dfn[u] = low[u] = ++ timestamp;
    stk[++ top] = u, in_stk[u] = true;
    for(int i = h[u]; ~ i; i = ne[i])
    {
        int v = e[i];
        if(!dfn[v])
        {
            tarjan(v);
            //如果low[v]更小,则使用low[v]更新low[u],因为u可以到达v,所以v能回溯到时间戳,u也必然能到
            low[u] = min(low[u], low[v]);
        }
        else if(in_stk[v]) //v点已经遍历过了,并且还在栈中,说明v是u的后向边或者横叉边连接的点
        {
             //那么v点的时间戳一定小于u点的时间戳
            low[u] = min(low[u], dfn[v]);
        }
    }
    if(dfn[u] == low[u]) //如果u能回溯到的最早时间戳就是自己,那么u必然是其所在强连通分量最早被访问的点
    {
        scc_cnt ++;
        int v; 
        do
        {
            v = stk[top --]; //弹出栈中该强连通分量中的点
            in_stk[v] = false;
            id[v] = scc_cnt;
            scc_size[scc_cnt]++; //统计该强连通分量中点的数量
        }while(u != v);
    }
    
}
int main()
{
    scanf("%d%d%d", &n, &m, &mod);
    memset(h, -1, sizeof h);
    memset(hd, -1, sizeof hd);
    while (m -- )
    {
        int a, b;
        scanf("%d%d", &a, &b);
        add(h, a, b);
    }
    
    for(int i = 1; i <= n; i ++)
        if(!dfn[i]) tarjan(i); //tarjan求强连通分量
    
    unordered_set<int> S; //保存每条边的哈希值,防止重边  
    //基于强连通分量构建DAG
    for(int u = 1; u <= n; u ++)
        for(int i = h[u]; ~ i; i = ne[i])
        {
            int v = e[i];
            int a = id[u], b = id[v];
            LL hash = a * 1000000ll + b; //分配一个哈希值
            if(a != b && !S.count(hash)) //不在同一个强连通分量中,并且不是重边
            {
                add(hd, a, b);
                S.insert(hash);
            }
        }
    //在拓扑序列中求解最长链的长度和方案数
    for(int u = scc_cnt; u > 0; u --)
    {
        if(!f[u]) //初始状态
        {
            f[u] = scc_size[u];
            g[u] = 1;
        }
        for(int i = hd[u]; ~ i; i = ne[i])
        {
            int v = e[i];
            if(f[v] < f[u] + scc_size[v])
            {
                f[v] = f[u] + scc_size[v];
                g[v] = g[u];
            }
            else if(f[v] == f[u] + scc_size[v])
            {
                g[v] = (g[v] + g[u]) % mod;
            }
        }
    }
    
    int maxn = 0, sum = 0; //求最长链的长度和方案数
    for(int i = 1; i <= scc_cnt; i ++)
    {
        if(f[i] > maxn)
        {
            maxn = f[i];
            sum = g[i];
        }
        else if(f[i] == maxn) sum = (sum + g[i]) % mod;
    }
    printf("%d\n%d\n", maxn, sum);
    return 0;
        
}

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

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

相关文章

番外篇 | 斯坦福提出即插即用二阶优化器Sophia :相比Adam实现2倍加速,显著节省大语言模型训练成本

前言:Hello大家好,我是小哥谈。大模型的预训练成本巨大,优化算法的改进可以加快模型的训练时间并减少训练开销。目前大模型的训练优化器基本上都采用Adam及其变体,并且Adam的应用已经有9个年头了,在模型优化方面相当于霸主的地位。但是能否够在优化器方面提高模型预训练效…

【每日刷题】Day79

【每日刷题】Day79 &#x1f955;个人主页&#xff1a;开敲&#x1f349; &#x1f525;所属专栏&#xff1a;每日刷题&#x1f34d; &#x1f33c;文章目录&#x1f33c; 1. 1619. 删除某些元素后的数组均值 - 力扣&#xff08;LeetCode&#xff09; 2. 1365. 有多少小于当前…

python3.8安装详细教程

python3.8下载及安装详细教程 Python 3.8 是一个重要的Python版本&#xff0c;它引入了一系列新功能和改进。以下是对Python 3.8的详细概述&#xff0c;包括其关键特性、安装方法以及版本状态等信息。 Python 3.8的关键特性 海象运算符&#xff08;Walrus Operator&#xff09…

保障性住房数字化运营平台助力租赁住房智能化管理

保障性住房能提供合理的价格、良好的配套设施和优越的租住体验&#xff0c;租赁将不是问题。 一、发力租赁型保障房建设 随着城镇化进程的加速和流动人口规模的扩大&#xff0c;进城务工人员、新就业大学生等新市民、青年人的住房困难问题日益凸显。加快发展租赁型保障性住房…

深圳技术大学oj C : 生成r子集

Description 输出给定序列按字典序的 &#xfffd; 组合&#xff0c;按照所有 &#xfffd; 个元素出现与否的 01 标记串 &#xfffd;&#xfffd;&#xfffd;&#xfffd;−1,...,&#xfffd;1 的字典序输出. 此处01串的字典序指&#xff1a;先输入的数字对应低位&#x…

使用高斯混合模型识别餐厅热点

使用 GMM 识别加拿大多伦多的直观餐厅集群&#xff08;附 Python 代码&#xff09; 聚类算法&#xff08;例如 GMM&#xff09;是一种有用的工具&#xff0c;可帮助识别数据中的模式。它们使我们能够识别数据集中的子组&#xff0c;从而提高你的理解或增强预测模型。在本文中&a…

中国国产AI芯片的崛起

一、CUDA的垄断 当讨论半导体行业面临的挑战时&#xff0c;你首先想到的是什么&#xff1f;光刻机&#xff1f;3纳米或者5纳米技术&#xff1f;我们无法生产的完美方形芯片&#xff1f;是的&#xff0c;但也不完全是。 人们经常把半导体芯片归类为硬件产业&#xff0c;但实际上…

mmcv安装失败及解决方案

假如想安装的版本是mmcv1.4.0, 但是pip install mmcv1.4.0总是失败&#xff0c;若是直接pip install mmcv会安装成功&#xff0c;但是安装的就是最新版本&#xff0c;后面代码跑起来还会报错&#xff0c;怎么办呢&#xff1f; 接下来分享一个mmcv指定版本安装的方式。 网页&a…

PCL小笔记

一、常用概念 1&#xff0c;过滤器Filters 消除噪音 2&#xff0c;特征Features 集合点属性&#xff1a;曲面的曲率估计和查询点的法线 通过k-neighborhood计算得到这两个属性作为特征 查找方法&#xff1a;KD-tress、八叉树等 3&#xff0c;关键点Keypoints 可以利用明确标…

ios-实验室暑假培训(1)

一 组队 在正式培训之前&#xff0c;也是数模比赛的众中之重。 一定要商讨好组队的相关事宜&#xff01;要求建模/编程/写作/写作三方能力交叉&#xff01; 而这三个当中&#xff0c;决定比赛拿奖上限的是编程手&#xff0c;决定比赛能不能拿奖的是写作手。而建模的更像是一个…

【JavaWeb】登录校验-会话技术(一)Cookie与Session

登录校验 实现登陆后才能访问后端系统页面&#xff0c;不登陆则跳转登陆页面进行登陆。 首先我们在宏观上先有一个认知&#xff1a; HTTP协议是无状态协议。即每一次请求都是独立的&#xff0c;下一次请求并不会携带上一次请求的数据。 因此当我们通过浏览器访问登录后&#…

Cyuyan中的自定义类型——结构体

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 前言一、结构体基础知识&#xff08;一&#xff09;、结构体类型的声明、变量的创建与初始化&#xff08;二&#xff09;、结构成员访问操作符&#xff08;三&#…

近红外光谱脑功能成像(fNIRS):1.光学原理、变量选取与预处理

一、朗伯-比尔定律与修正的朗伯-比尔定律 朗伯-比尔定律 是一个描述光通过溶液时被吸收的规律。想象你有一杯有色液体&#xff0c;比如一杯红茶。当你用一束光照射这杯液体时&#xff0c;光的一部分会被液体吸收&#xff0c;导致透过液体的光变弱。朗伯-比尔定律告诉我们&#…

如何在主动动态安全中使用人工智能驱动的威胁分类提高防御精准度

面对当今世界不断演变的网络威胁&#xff0c;人工智能和网络安全将会发挥重要的防护作用。在数据泄露和网络攻击日益突出的时代&#xff0c;人工智能和网络安全之间的合作成为数字安全战场上的强大盟友。 本文将深入研究这两个领域的融合&#xff0c;揭示它们在彻底改变威胁检测…

未来的钥匙在于过去:学历史的真正意义,震惊!历史竟然是偶然的?从历史中寻找未来的方向!

我们自幼接受的教育是&#xff0c;学历史是为了相信历史是必然的。中国人民必然战胜日寇的侵略&#xff0c;解放思想和改革开放必定会发生&#xff0c;和平和发展必定是世界的主题&#xff0c;中国经济必定是高速增长…… 然而&#xff0c;在真正的历史学家眼中&#xff0c;历史…

什么是 Socks5 代理?了解和使用 SOCKS5 代理的终极指南

SOCKS5是什么以及它如何工作&#xff1f; 在网络和互联网协议领域&#xff0c;有多种工具和技术在确保安全高效的通信方面发挥着至关重要的作用。 SOCKS5 就是这样一个工具&#xff0c;它代表套接字安全版本 5。 在这篇博文中&#xff0c;我们将深入探讨 SOCKS5 的细节&…

实战项目——用Java实现图书管理系统

前言 首先既然是管理系统&#xff0c;那咱们就要实现以下这几个功能了--> 分析 1.首先是用户分为两种&#xff0c;一个是管理员&#xff0c;另一个是普通用户&#xff0c;既如此&#xff0c;可以定义一个用户类&#xff08;user&#xff09;&#xff0c;在定义管理员类&am…

【后端面试题】【中间件】【NoSQL】MongoDB提高可用性的方案(主从结构、仲裁节点、分片、写入语义)

主从结构 MongoDB的高可用和别的中间件的高可用方案基本类似。比如在MySQL里&#xff0c;接触了分库分表和主从同步&#xff1b;在Redis里&#xff0c;Redis也有主从结构&#xff1b;在Kafka里&#xff0c;分区也是有主从结构的。 所以先介绍启用了主从同步 我们的系统有一个关…

【AIGC】DiffuToon:稳定的视频卡通化技术方案

论文&#xff1a;https://arxiv.org/pdf/2401.16224 github&#xff1a;https://github.com/modelscope/DiffSynth-Studio/tree/main/examples/Diffutoon 网络结构 两个主要分支&#xff1a;主要的卡通化管线和编辑分支 重要技术 使用了fastblend(无需模型的视频帧之间的平滑…

巴图自动化Profinet协议转Modbus协议模块接称重模块与PLC通讯

巴图自动化Profinet协议转Modbus协议模块&#xff08;BT-MDPN10&#xff09;是一种能够实现Modbus协议和Profinet协议之间转换的设备。Profinet协议转Modbus协议模块可提供单个或多个RS485接口&#xff0c;使得不同设备之间可以顺利进行通信&#xff0c;进一步提升了工业自动化…