DAG最小路径点覆盖,最小路径可重复覆盖,详解

文章目录

    • 前言
    • 有向无环图的最小路径点覆盖
      • 概念
      • 拆点二分图
      • 定理
        • **证明**
      • 最小路径可重复覆盖
        • 解决策略
        • 代码实现
    • OJ练习

前言

关于二分图:二分图及染色法判定

关于二分图最大匹配:二分图最大匹配——匈牙利算法详解

关于二分图带权最大完备匹配:二分图带权最大匹配-KM算法详解


有向无环图的最小路径点覆盖

概念

给定一张有向无环图,要求用尽量少的不相交的简单路径,覆盖有向无环图的所有顶点(也就是每个顶点恰好被覆盖一次)。这个问题被称为有向无环图的最小路径点覆盖,简称**“最小路径覆盖”**。

拆点二分图

设原来的有向无环图为G = (V , E), n = |V|。 把G中的每个点x拆成编号为x和x+n的两个点。建立一张新的二分图,1~n作为二分图左部点,n + 1 ~ 2n作为二分图右部点,对于原图的每条有向边(x,y), 在二分图的左部点x与右部点y+n之间连边。最终得到的二分图称为G的拆点二分图,记为G’。例如:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

定理

有向无环图G的最小路径点覆盖包含的路径条数,等于n减去拆点二分图G’的最大匹配数。

证明

在有向无环图G= (V,E)的最小路径覆盖中,对于任意的x ∈ V,因为路径不相交,所以x的入度和出度都不超过1。因为每个节点都被覆盖,所以x的入度和出度至少有一个是1
因此,最小路径覆盖中的所有边,在拆点二分图G‘中构成一组匹配。最小路径覆盖中每条边(x,y) 的起点x与拆点二分图每条匹配边(x,y+n)的左部点x是一一对应的
特别地,对于每条路径的终点t,因为t没有出边,所以在二分图中,t匹配失败。即路径的终点和拆点二分图左部的非匹配点是一一对应的。

故有:路径覆盖包含的路径条数最少

等价于 路径的终点数(出度为0的点数)最少

等价于 拆点二分图左部非匹配点最少

等价于 拆点二分图匹配数最大

G的最小路径覆盖的路径数等于n减去拆点二分图G‘的最大匹配数
证毕。

最小路径可重复覆盖

给定一张有向无环图,要求用尽量少的可相交的简单路径,覆盖有向无环图的所有顶点(也就是一个节点可以被覆盖多次)。这个问题被称为有向无环图的最小路径可重复点覆盖

解决策略

在最小路径可重复点覆盖中,若两条路径:…→u→p→v→…和…→x→p→y→…在点p相交,则我们在原图中添加一条边(x,y),让第二条路径直接走x→y,就可以避免重复覆盖点p。

进一步地,如果我们把原图中所有间接连通的点对x,y直接连上有向边(x,y),那么任何“有路径相交的点覆盖”一定都能转化成“没有路径相交的点覆盖”。实际上,转化后的拆点二分图的未匹配左部点仍为最小可相交路径数目,例如:外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

综上所述,有向无环图G的最小路径可重复点覆盖等价于先对有向图传递闭包得到有向无环图G’,再在G’上求一般的(路径不可相交的)最小路径点覆盖

代码实现

#define int long long
#define N 205

int n, m, match[N]{0}, ans = 0;
bool vis[N], g[N][N]{0};//邻接矩阵存图
//匈牙利
bool dfs(int u)
{
    for (int v = 1; v <= n; v++)
        if (!vis[v] && g[u][v])
        {
            vis[v] = true;
            if (!match[v] || dfs(match[v]))
            {
                match[v] = u;
                return true;
            }
        }
    return false;
}

//main
    // Floyd求传递闭包
    for (int i = 1; i <= n; i++)
        g[i][i] = true;

    for (int k = 1; k <= n; k++)
        for (int i = 1; i <= n; i++)
            for (int j = 1; j <= n; j++)
                g[i][j] |= g[i][k] && g[k][j];

    for (int i = 1; i <= n; i++)
        g[i][i] = false;

    for (int i = 1; i <= n; i++)
        memset(vis, 0, sizeof(vis)), ans += dfs(i);

    cout << n - ans;

OJ练习

379. 捉迷藏 - AcWing题库

这道题目的最大藏身点数目就是给定的有向无环图的最小路径可重复覆盖数目。

设最大藏身点集合为hide,最小路径可重复覆盖为path,往证hide = path:

显然藏身点不能在同一条路径上,而path包含了所有的点,所以每条path最多选一个藏身点,故|hide| <= |path|

如果我们能在path上构造出|path|个藏身点,那么就得证了,因为|hide|是最大藏身点数目,而最大又不超过|path|。

求path很容易,我们即然能求出最小覆盖,自然能还原出路径:

  1. 对于每条path的终点即为拆点二分图非匹配点,这个显然很好求
  2. 非匹配点x的右部拆点为x + n,那么通过match[x + n]可以找到x在path的邻接点y,同样的方法一直往下进行,可以还原出path

问题在于如何从每条path上选出一个藏身点:

  1. 记path终点集合为E,从E发出的边往下走,访问到的节点集合为next(E)
  2. 若E ∩ next(E) = Ø,即藏身点之间无路径,那么E 可以作为 hide
  3. 否则,对于E ∩ next(E)中的 每个节点e,沿着路径往回走,总能找到e’ ∉ next(E),否则path数目会减少,和最小覆盖矛盾
  4. 找到e’后删除e,再重复3,直到E ∩ next(E) = Ø,此时E即为符合条件的hide

证毕

AC代码如下:

#include <iostream>
#include <string>
#include <cstring>
#include <algorithm>
#include <climits>
#include <cmath>
#include <functional>
using namespace std;
#define int long long
#define N 205

int n, m, match[N]{0}, ans = 0;
bool vis[N], g[N][N]{0};

bool dfs(int u)
{
    for (int v = 1; v <= n; v++)
        if (!vis[v] && g[u][v])
        {
            vis[v] = true;
            if (!match[v] || dfs(match[v]))
            {
                match[v] = u;
                return true;
            }
        }
    return false;
}

signed main()
{
    ios::sync_with_stdio(false);
    cin.tie(0), cout.tie(0);
    //freopen("in.txt", "r", stdin);

    cin >> n >> m;
    for (int i = 0, a, b; i < m; i++)
    {
        cin >> a >> b;
        g[a][b] = true;
    }
    for (int i = 1; i <= n; i++)
        g[i][i] = true;

    // 传递闭包
    for (int k = 1; k <= n; k++)
        for (int i = 1; i <= n; i++)
            for (int j = 1; j <= n; j++)
                g[i][j] |= g[i][k] && g[k][j];

    for (int i = 1; i <= n; i++)
        g[i][i] = false;

    for (int i = 1; i <= n; i++)
        memset(vis, 0, sizeof(vis)), ans += dfs(i);

    cout << n - ans;
    return 0;
}

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

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

相关文章

NFS网络共享服务存储

目录 一、NFS简介 1、NFS定义&#xff1a; 2、NFS的特点 3、NFS的优缺点 4、NFS的原理图示 二、服务端NFS配置文件&#xff1a;/etc/exports 三、实验&#xff1a;NFS共享存储服务配置 1、服务端安装nfs-utils与rpcbind软件包 2、服务端新建共享文件夹目录并赋予权限 …

前端(html+css+javascript)作业--展现家乡的网页

期末期间&#xff0c;老师布置了前端作业&#xff0c;现在放到这里&#xff0c;给各位同志参考。 桂平市是广西壮族自治区的一个美丽的城市&#xff0c;拥有丰富的历史文化和自然景观&#xff0c;属于贵港市管辖&#xff0c;那为什么是看起来是市级而不是县级&#xff0c;其实他…

HAL库配置RS485通信

在配置好串口的基础上完成RS485的配置 一、使能RS485的发送和接收模式引脚 __HAL_RCC_GPIOG_CLK_ENABLE();//高电平是发送模式&#xff0c;低电平是接收模式&#xff0c;默认是接收模式HAL_GPIO_WritePin(PG4_RS485_DIR1_Port, PG4_RS485_DIR1_Pin, GPIO_PIN_RESET);GPIO_Init…

Java基础面试题(三)

Java基础面试题&#xff08;三&#xff09; 文章目录 Java基础面试题&#xff08;三&#xff09;什么是字节码?采用字节码的好处是什么?为什么说 Java 语言“编译与解释并存”&#xff1f; 文章来自Java Guide 用于学习如有侵权&#xff0c;立即删除 什么是字节码?采用字节码…

Qt命令行安装:linux(ubuntu)

起因是我上一篇文章说的&#xff0c;官网下的安装包卡死在第一步安装界面了。 于是我就问GPT有没有纯命令行的安装方式&#xff0c;果然是有的。 在Ubuntu上安装Qt可以使用以下命令&#xff1a; 1. 首先&#xff0c;添加Qt的官方存储库到系统中&#xff1a; sudo add-apt-rep…

在Ubuntu下载Python3.6 并建立软连接

打开终端&#xff0c;输入su root,进入root模式 su root为了避免权限问题 安装zlib1g-dev apt-get install zlib1g-dev1.然后创建目录 mkdir -p /usr/local/python32.进入python3目录 cd /usr/local/python33.从官网下载好python3.6.2 wget https://www.python.org/ftp/p…

Qt QRubberBand 如何实现鼠标框选控件

QRubberBand类提供了一个矩形或直线&#xff0c;可以指示选择或边界。常见的模式是结合鼠标事件来执行此操作。本文将使用框选QCheckBox控件&#xff0c;来演示QRubberBand是如何配合鼠标进行工作的。 一、RubberBand 框选效果图 二、RubberBand 代码 rubberband.h #ifndef …

【ug572】UltraScale体系结构时钟资源手册节选

概述 时钟架构概述 The UltraScale architecture clocking resources manage complex and simple clocking requirements with dedicated global clocks distributed on clock routing and clock distribution resources. The clock management tiles (CMTs) provide clock f…

经典目标检测YOLO系列(二)YOLOv2算法详解

经典目标检测YOLO系列(二)YOLOv2算法详解 YOLO-V1以完全端到端的模式实现达到实时水平的目标检测。但是&#xff0c;YOLO-V1为追求速度而牺牲了部分检测精度&#xff0c;在检测速度广受赞誉的同时&#xff0c;其检测精度也饱受诟病。正是由于这个原因&#xff0c;YOLO团队在20…

【RT-DETR有效改进】移动设备网络ShuffleNetV1(超轻量化网络主干)

前言 大家好&#xff0c;这里是RT-DETR有效涨点专栏。 本专栏的内容为根据ultralytics版本的RT-DETR进行改进&#xff0c;内容持续更新&#xff0c;每周更新文章数量3-10篇。 专栏以ResNet18、ResNet50为基础修改版本&#xff0c;同时修改内容也支持ResNet32、ResNet101和PP…

5路开关量输入转继电器输出 Modbus TCP远程I/O模块 YL95 传感器信号的测量

特点&#xff1a; ● 五路开关量输入&#xff0c;五路继电器输出 ● 支持Modbus TCP 通讯协议 ● 内置网页功能&#xff0c;可以通过网页查询电平状态 ● 可以通过网页设定继电器输出状态 ● DI信号输入&#xff0c;DO输出及电源之间互相隔离 ● 宽电源供电范围&#x…

django rest_framework 部署doc文档

1.背景 在实际开发过程中&#xff0c;前后端分离的项目&#xff0c;是需要将一份完整的接口文档交付给前端开发人员&#xff0c;这样有利于开发速度和开发质量&#xff0c;以及有可能减少协同时间。 2.内容 本项目是以Pythondjangorest_framework作为技术框架&#xff0c;在这…

VMware workstation安装Endeavouros-Galileo-11虚拟机并配置网络

VMware workstation安装Endeavouros-Galileo-11虚拟机并配置网络 EndeavourOS是基于Arch Linux的滚动式Linux发行。基于Arch来提供方便的安装及预配置好的桌面环境。EndeavourOS通过Calamares图形系统安装器来安装&#xff0c;缺省使用Xfce桌面。该文档适用于在VMware worksta…

61. 旋转链表

题目 给你一个链表的头节点 head &#xff0c;旋转链表&#xff0c;将链表每个节点向右移动 k 个位置。 示例 1&#xff1a; 输入&#xff1a;head [1,2,3,4,5], k 2 输出&#xff1a;[4,5,1,2,3]示例 2&#xff1a; 输入&#xff1a;head [0,1,2], k 4 输出&#xff1a;…

基于大数据平台(XSailboat)的计算管道实现MySQL数据源的CDC同步--flink CDC

1. 背景 笔者在先前的一篇文档《数据标签设计 – 大数据平台(XSailboat)的数据标签模块》 提到了关于数据标签的模块&#xff0c;现已实现并应用于项目中。在项目中遇到这样一种情形&#xff1a; 在业务系统中&#xff0c;对某类对象打了标签&#xff0c;现在需要对这类对象进…

IOS-高德地图路径绘制-Swift

本文展示的是在IOS开发中调用高德地图进行驾车路径绘制&#xff0c;开发语言是Swift。 IOS高德地图集成请看&#xff1a;IOS集成高德地图Api 使用路径规划功能需要集成高德地图的搜索功能。 pod AMapSearch定义AMapSearchAPI 定义主搜索对象 AMapSearchAPI &#xff0c;并继承…

Android 13.0 Launcher3 电话和短信app图标显示未读短信和未接来电的条数

1.概述 在13.0系统产品rom定制化开发中,最近客户有需求要求在电话app图标显示未接来电的条数 在短信app图标上显示未读信息的条数 根据需求首选要在Launcher3的Launcher.java中,启动launcher时,查询未读短信和未接来电 在有未接来电时,更新未接来电的数量 在有未读短信时,…

浏览器网页内嵌Qt-C++音视频播放器的实现,支持软硬解码,支持音频,支持录像截图,支持多路播放等,提供源码工程下载

一.前言 在浏览器中实现播放RTSP实时视频流&#xff0c;⼤体上有如下⼏个⽅案&#xff1a; ⽅案一&#xff1a;浏览器插件⽅案 ActiveX、NPAPI、PPAPI ActiveX插件适用于IE浏览器&#xff0c;NPAPI与PPAPI插件适用于谷歌浏览器&#xff0c;不过这些插件都已经不被浏览器所支持…

【Discuz插件】价值299的论坛积分商城

第一步&#xff1a;首先利用上传工具FTP&#xff0c;将插件上传至网站空间&#xff08;相信你会搭建论坛&#xff0c;这步应该不是问题&#xff0c;此处滤过&#xff09; 第二步&#xff1a;找到source文件夹。双击source&#xff0c;可以看到有许多文件&#xff0c;找到plugi…

找不到msvcr100.dll怎么办?msvcr100.dll丢失的解决方法

在面对计算机系统中“msvcr100.dll”文件缺失这一常见问题时&#xff0c;用户可能会遇到应用程序无法正常启动或运行的情况。为了解决这一困扰广大用户的难题&#xff0c;本文将详细介绍并解析找不到“msvcr100.dll”文件的5种有效解决方法。 一、了解一下msvcr100.dll是什么&a…