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

题目链接

最大半连通子图

题目描述

一个有向图 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.mfbz.cn/a/769038.html

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

相关文章

Go语言实现钉钉机器人接入Dify工作流

go语言实现实现钉钉机器人接入dify工作流&#xff0c;完成ai 流式问答 代码地址 有用的话点个star github地址 效果 配置使用 修改.env_template文件 为.env 设置.env文件内的环境变量 API_KEY: dify的api_keyAPI_URL: dify 的api接口CLIENT_ID : 钉钉机器人应用的idCLIENT…

基于Java的家政预约系统设计与实现

作者介绍&#xff1a;计算机专业研究生&#xff0c;现企业打工人&#xff0c;从事Java全栈开发 主要内容&#xff1a;技术学习笔记、Java实战项目、项目问题解决记录、AI、简历模板、简历指导、技术交流、论文交流&#xff08;SCI论文两篇&#xff09; 上点关注下点赞 生活越过…

Docker-compose 实现Prometheus+Grafana监控MySQL及Linux主机

. ├── Grafana │ ├── data │ └── docker-compose.yaml ├── Mysql │ ├── conf │ ├── data │ ├── docker-compose.yaml │ └── logs ├── Mysqld_exporter │ ├── conf │ └── docker-compose.yaml ├── node-exporter │…

RPA 第一课

RPA 是 Robotic Process Automation 的简称&#xff0c;意思是「机器人流程自动化」。 顾名思义&#xff0c;它是一种以机器人&#xff08;软件&#xff09;来替代人&#xff0c;实现重复工作自动化的工具。 首先要说一句&#xff0c;RPA 不是 ChatGPT 出来之后的产物&#x…

推荐三款常用接口测试工具!

接口测试是软件开发中至关重要的一环&#xff0c;通过对应用程序接口进行测试&#xff0c;可以验证其功能、性能和稳定性。随着互联网和移动应用的快速发展&#xff0c;接口测试变得越来越重要。为了提高测试效率和质量&#xff0c;开发人员和测试人员需要使用专业的接口测试工…

自然语言处理学习(2)基本知识 文本预处理+文本数据分析+文本增强

conda activate DL conda deactivate课程链接 一 一些包的安装 1 stanfordcorenlp 在anoconda prompt 里面&#xff1a;进入自己的conda环境&#xff0c;pip install stanfordcorenlp 进入方式 相关包下载&#xff0c;Jar包我没有下载下来&#xff0c;太慢了&#xff0c;这个…

提高Python爬虫的匿名性:代理ip的配置策略

在数字化时代的今天&#xff0c;网络数据采集已成为获取信息的重要手段&#xff0c;尤其在竞争激烈的商业环境中。Python作为一种强大的编程语言&#xff0c;广泛应用于开发各种数据爬虫来自动化地抓取网络信息。然而&#xff0c;随着网站安全意识的提高&#xff0c;越来越多的…

牛客小白月赛97

A.三角形 判断等边三角形&#xff0c;题不难&#xff0c;代码如下&#xff1a; #include <iostream>using namespace std;int a[110];int main() {int n;cin >> n;int x;int mx 0;for(int i 1; i < n; i){cin >> x;mx max(mx, x);a[x];}for(int i 1…

Java OnVif应用PTZ控制

研究OnVif在Java程序中应用&#xff0c;在此作记录&#xff0c;onvif-java-lib/release at master milg0/onvif-java-lib GitHub&#xff0c;在此连接中下载jar&#xff0c;并在项目中引用&#xff0c;该jar封装很好&#xff0c;可以方便快速完成功能 1.登录OnVif 2.PTZ控制…

【大数据】—美国交通事故分析(2016 年 2 月至 2020 年 12 月)

引言 在当今快速发展的数字时代&#xff0c;大数据已成为我们理解世界、做出决策的重要工具。特别是在交通安全领域&#xff0c;大数据分析能够揭示事故模式、识别风险因素&#xff0c;并帮助制定预防措施&#xff0c;从而挽救生命。本文将深入探讨2016年2月至2020年12月期间&…

反射(通俗易懂)

一、反射(Reflection) 反射就是:加载类&#xff0c;并允许以编程的方式解剖类中的各种成分(成员变量、方法、构造器等) 动态语言&#xff0c;是一类在运行时可以改变其结构的语言&#xff1a;例如新的函数、对象、甚至代码可以被引进&#xff0c;已有的函数可以被删除或是其他…

强化学习的数学原理:值迭代与策略迭代

概述 从课程地图上可以看出来&#xff0c;这是本门课程中第一次正式的介绍强化学习的算法&#xff0c;并且是一个 model-based 的算法&#xff0c;而在下一节课将会介绍第一个 model-free 的算法&#xff08;在 chapter 5&#xff09;。而这两节和之前所学的 BOE 是密切相关的&…

笔记-python爬虫概述

目录 常用第三方库 爬虫框架 动态页面渲染1. url请求分析2. selenium3. phantomjs4. splash5. spynner 爬虫防屏蔽策略1. 修改User-Agent2. 禁止cookies3. 设置请求时间间隔4. 代理IP池5. 使用Selenium6. 破解验证码常用第三方库 对于爬虫初学者&#xff0c;建议在了解爬虫原…

DEX: Scalable Range Indexing on Disaggregated Memory——论文泛读

arXiv Paper 论文阅读笔记整理 问题 内存优化索引[2&#xff0c;3&#xff0c;18&#xff0c;27&#xff0c;42]对于加速OLTP至关重要&#xff0c;但随着数据大小&#xff08;以及索引大小&#xff09;的增长&#xff0c;对内存容量的需求可能会超过单个服务器所能提供的容量…

基于ADRC自抗扰算法的UAV飞行姿态控制系统simulink建模与仿真

目录 1.课题概述 2.系统仿真结果 3.核心程序与模型 4.系统原理简介 4.1 控制系统概述 4.2 ADRC基本框架 4.3 控制律设计 5.完整工程文件 1.课题概述 基于ADRC自抗扰算法的UAV飞行姿态控制系统simulink建模与仿真&#xff0c;分别对YAW&#xff0c;PITCH&#xff0c;ROL…

golang写的自动更新器

文件自动更新器&#xff0c;这个很多端游和软件都有用到的。 golang的rpc通信&#xff0c;是非常好用的一个东西&#xff0c;可以跟调用本地函数一样&#xff0c;调用远程服务端的函数&#xff0c;直接从远程服务端上拉取数据下来&#xff0c;简单便捷。 唯一的遗憾就是&#x…

互联网盲盒小程序的市场发展前景如何?

近几年来&#xff0c;盲盒成为了大众热衷的消费市场。盲盒是一个具有随机性和惊喜感&#xff0c;它能够激发消费者的好奇心&#xff0c;在拆盲盒的过程中给消费者带来巨大的愉悦感&#xff0c;在各种的吸引力下&#xff0c;消费者也愿意为各类盲盒买单。如今&#xff0c;随着盲…

暑假提升(2)[平衡二叉树之一--AVL树]

我不去想未来是平坦还是泥泞&#xff0c;只要热爱生命一切&#xff0c;都在意料之中。——汪国真 AVLTree 1、诞生原因2、什么是AVL树3、如何设计AVL树3、1、AVL树节点的定义3、2、AVL树的插入3、3、平衡因子那些事3、3、1、平衡因子-2/2下的简单情况3、3、2、平衡因子-2/2下的…

tkinter拖入txt文本并显示

tkinter拖入txt文本并显示 效果代码 效果 代码 import tkinter as tk from tkinter import scrolledtext from tkinterdnd2 import DND_FILES, TkinterDnDdef drop(event):file_path event.data.strip({})if file_path.endswith(.txt):with open(file_path, r, encodingutf-8…

K8s 的最后一片拼图:dbPaaS

K8s 的发展使得私有云跟公共云之间的技术差不断的缩小&#xff0c;不管是在私有云还是公共云&#xff0c;大家今天都在基于 K8s 去开发 PaaS 系统。而 K8s 作为构建 PaaS 的基础&#xff0c;其全景图里还缺最后一块“拼图”——dbPaaS。作为一个云数据库行业干了十几年的资深从…