第三章 图论 No.11二分图,匈牙利算法与点覆盖

news2024/11/26 20:45:42

文章目录

    • 二分+染色:257. 关押罪犯
    • 增广路径
      • 372. 棋盘覆盖
    • 最小点覆盖
      • 376. 机器任务
    • 最大独立集
      • 378. 骑士放置
    • 最小路径点覆盖

image.png

二分+染色:257. 关押罪犯

257. 关押罪犯 - AcWing题库
image.png

最大最小问题,一眼二分
答案的范围在 [ 1 , 1 e 9 ] [1, 1e9] [1,1e9]之间,二分答案,check(mid)
check:将所有权值大于mid的边进行二分,若能得到二分图,返回true,否则返回false
最终将得到最优解ans,所有大于ans的边组成的图为二分图,若是图中有边的权值小于ans,那么这个图就不是二分图
当ans为0时,说明原图就是一张二分图,此时的答案也为0,不需要特判,所以二分的区间为 [ 0 , 1 e 9 ] [0, 1e9] [0,1e9]

#include <iostream>
#include <cstring>
using namespace std;

const int N = 20010, M = 2e5 + 10;
int h[N], e[M], ne[M], w[M], idx;
int color[N];
int n, m;

void add(int x, int y, int d)
{
    e[idx] = y, ne[idx] = h[x], w[idx] = d, h[x] = idx ++ ;
}

bool dfs(int x, int c, int mid)
{
    color[x] = c;
    for (int i = h[x]; i != -1; i = ne[i])
    {
        if (w[i] <= mid) continue;
        int y = e[i];
        if (!color[y])
        {
            if (!dfs(y, 3 - c, mid)) return false;
        }
        else if (color[y] == c) return false;
    }
    return true;
}

bool check(int mid)
{
    memset(color, 0, sizeof(color));
    for (int i = 1; i <= n; ++ i )
        if (!color[i])
            if (!dfs(i, 1, mid))
                return false;
                
    return true;
}

int main()
{
    memset(h, -1, sizeof(h));
    scanf("%d%d", &n, &m);
    int x, y, d;
    for (int i = 0; i < m; ++ i )
    {
        scanf("%d%d%d", &x, &y, &d);
        add(x, y, d), add(y, x, d);
    }
    
    int l = 0, r = 1e9;
    while (l < r)
    {
        int mid = l + r >> 1;
        if (check(mid)) r = mid;
        else l = mid + 1;
    }
    printf("%d\n", l);
    
    return 0;
}

增广路径

从二分图的非匹配点开始,经过非匹配边,匹配边,非匹配边,匹配边…最后到非匹配点的路径被称为增广路径
image.png
将所有匹配边删除,添加非匹配边,图中匹配的对数+1
最大匹配不存在增广路径


372. 棋盘覆盖

372. 棋盘覆盖 - AcWing题库
image.png

建图方式很特殊,将每个格子看成点,相邻格子之间连一条边,问题就转换成了从图中选择最多的边,使得每条边的点都不重复
这就是一个最大匹配问题
接着判断图是否是一个二分图,若不是二分图,那么不能使用匈牙利算法
n*m矩阵的奇数格和偶数格(横纵坐标之和)染上不同的颜色,相同颜色的为一组,那么整个矩阵就能被分成两个集合,由于只有相邻格子之间存在边,所以集合中的不存在边,只有集合之间存在边
image.png

枚举所有奇数格(或者偶数格),试着将其匹配。注意:不需要枚举坏掉的格子,匹配时也不用匹配坏掉的格子

#include <iostream>
#include <cstring>
using namespace std;

const int N = 110;
typedef pair<int, int> PII;
PII match[N][N];
bool g[N][N], st[N][N];
int dx[4] = { 0, 1, 0, -1 }, dy[4] = { 1, 0, -1, 0 };
int n, m;
    
bool find(int x, int y)
{
    for (int i = 0; i < 4; ++ i )
    {
        int nx = x + dx[i], ny = y + dy[i];
        if (!g[nx][ny] && nx >= 1 && nx <= n && ny >= 1 && ny <= n)
        {
            if (!st[nx][ny])
            {
                auto t = match[nx][ny];
                st[nx][ny] = true;
                if (t.first == 0 || find(t.first, t.second))
                {
                    match[nx][ny] = { x, y };
                    return true;
                }
            }
        }
    }
    return false;
}

int main()
{
    scanf("%d%d", &n, &m);
    int x, y;
    while (m -- )
    {
        scanf("%d%d", &x, &y);
        g[x][y] = true;
    }
    
    
    int res = 0;
    for (int i = 1; i <= n; ++ i )
        for (int j = 1; j <= n; ++ j )
            if ((i + j) % 2 && !g[i][j])
            {
                memset(st, false, sizeof(st));
                if (find(i, j)) res ++ ;
            }
                
    printf("%d\n", res);
    return 0;
}

debug:find的判断条件if (!g[nx][ny] && nx >= 1 && nx <= n && ny >= 1 && ny <= n)!g[nx][ny]写成了!g[x][y]
每次find之前st数组没有重置


最小点覆盖

给定一个无向图,从中选出最少的点,使得每条边只有一个端点被选择
结论:最小点覆盖 = 最大匹配数


376. 机器任务

376. 机器任务 - AcWing题库
image.png

分析题意:有k个任务,每个任务可以在A机器或者B机器上完成,但是机器必须调整为相应的模式,任务的执行顺序任意,求任意顺序中的最少调整次数

建图:将完成每个任务需要调整的模式看成点,一个任务有两个点,在这两点之间连线。显然,得到的图是一个二分图,由于不同任务在相同机器上需要调整的模式可能相同,这些点可以看成一个点
题目要完成所有任务,即选择每条边的一个点,根据题意也就是求最小点覆盖
用匈牙利求二分图的最大匹配即可
由于每台机器的初始状态为0,所以需要调整状态为0的任务不用切换模式,直接就能完成,因此建图时不需要建立这些任务

#include <iostream>
#include <cstring>
using namespace std;

const int N = 210, M = 1010;
int h[N], e[M], ne[M], idx;
int match[N]; bool st[N];
int n1, n2, m;

void add(int x, int y)
{
    e[idx] = y, ne[idx] = h[x], h[x] = idx ++ ;
}

bool find(int x)
{
    for (int i = h[x]; i != -1; i = ne[i])
    {
        int y = e[i];
        if (!st[y])
        {
            st[y] = true;
            if (match[y] == 0 || find(match[y]))
            {
                match[y] = x;
                return true;
            }
        }
    }
    return false;
}

int main()
{
    
    while (scanf("%d", &n1), n1)
    {
        idx = 0;
        memset(h, -1, sizeof(h));
        memset(match, 0, sizeof(match));
        scanf("%d%d", &n2, &m);
        int t, x, y;
        while (m -- )
        {
            scanf("%d%d%d", &t, &x, &y);
            if (x == 0 || y == 0) continue;
            add(x, y);
        }
        
        int res = 0;
        for (int i = 1; i <= n1; ++ i)
        {
            memset(st, false, sizeof(st));
            if (find(i)) res ++ ;
        }
        printf("%d\n", res);
    }
    
    return 0;
}

最大独立集

从一个无向图中选出最多的点,使得选出的点之间都没有边
等价于去掉最少的点,将所有边破坏
等价于最小点覆盖,等价于最大匹配
假设一共n个点,最大匹配数位m,最大独立集的数量为n - m
最大团
从一个无向图中选出最多的点,使得选出的点之间都有边


378. 骑士放置

378. 骑士放置 - AcWing题库
image.png

建图:矩阵中,能互相攻击到的格子之间建立一条边
那么问题就转换成了求图的最大独立集,即选择的格子之间都没有边,不能相互攻击
image.png

验证建的图是否为二分图,将奇数格和偶数格染不同的颜色,若当前坐标为 ( x , y ) (x, y) (x,y),那么该坐标之和为 x + y x + y x+y,要得到与之相连的坐标,就要将x±1,y±2,坐标之和要±一个奇数
假设坐标之和为奇数,加上奇数得到偶数,格子的颜色不同
假设坐标之和为偶数,加上奇数得到奇数,格子的颜色也不同
所以该图是一个二分图,可以使用匈牙利算法求最大匹配

#include <iostream>
#include <cstring>
using namespace std;

typedef pair<int, int> PII;
const int N = 110;
bool g[N][N], st[N][N];
PII match[N][N];
int dx[8] = { 1, 1, 2, 2, -1, -1, -2, -2 }, dy[8] = { 2, -2, 1, -1, 2, -2, 1, -1 };
int n, m, t;

bool find(int x, int y)
{
    for (int i = 0; i < 8; ++ i )
    {
        int nx = x + dx[i], ny = y + dy[i];
        if (!g[nx][ny] && nx >= 1 && nx <= n && ny >= 1 && ny <= m)
        {
            if (!st[nx][ny])
            {
                st[nx][ny] = true;
                auto t = match[nx][ny];
                if (t.first == 0 || find(t.first, t.second))
                {
                    match[nx][ny] = { x, y };
                    return true;
                }
            }
        }
    }
    return false;
}

int main()
{
    scanf("%d%d%d", &n, &m, &t);
    int x, y;
    for (int i = 0; i < t; ++ i )
    {
        scanf("%d%d", &x, &y);
        g[x][y] = true;
    }
    int res = 0;
    for (int i = 1; i <= n; ++ i )
        for (int j = 1; j <= m; ++ j )
            if (!g[i][j] && (i + j) % 2)
            {
                memset(st, 0, sizeof(st));
                if (find(i, j)) res ++ ;
            }
            
    printf("%d\n", n * m - t- res);
    return 0;
}

debug:求最大匹配时,只需要遍历一个集合中的点,可以是奇数格也可以是偶数格,即添加条件(i + j) % 2


最小路径点覆盖

针对有向无环图,用最少的互不相交(点不重复)的路径较所有点覆盖
没听懂,先跳过

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

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

相关文章

数据驱动与关键字驱动

初次接触自动化测试时&#xff0c;对数据驱动和关键字驱动不甚理解&#xff0c;觉得有点故弄玄须&#xff0c;不就是参数和函数其嘛&#xff01;其实其也体现了测试所不同与开发的一些特点&#xff08;主要指系统测试&#xff09;&#xff0c;以及和对技术发展的脉络的展现。 …

MyBatisPlus通用枚举

数据库表中加一个字段sex&#xff08;为int类型&#xff09; 新加一个枚举的包&#xff0c;然后创建类的时候选择枚举类 Getter public enum SexEnum {MALE(1, "男"),FEMALE(2, "女");EnumValue//将注解标识的属性的值存储到数据库中private Integer sex;…

JZ36二叉搜索树与双向链表

题目地址&#xff1a;二叉搜索树与双向链表_牛客题霸_牛客网 题目回顾&#xff1a; 解题思路&#xff1a; 由题目可知&#xff0c;这里的二叉搜索树转成双向链表的符合左根右的逻辑顺序&#xff0c;且是一个递增序列。 创建两个指针&#xff0c;一个指向head&#xff0c;一个…

手把手教你,Selenium 遇见伪元素该如何处理?

问题发生 在很多前端页面中&#xff0c;大家会见到很多&#xff1a;:before、::after 元素&#xff0c;比如【百度流量研究院】&#xff1a; 比如【百度疫情大数据平台】&#xff1a; 如果你想学习自动化测试&#xff0c;我这边给你推荐一套视频&#xff0c;这个视频可以说是B…

NLP文本分类

NLP文本分类 落地实战五大利器&#xff01;_kaiyuan_sjtu的博客-CSDN博客https://zhuanlan.zhihu.com/p/432619164 https://github.com/alibaba/EasyNLP/blob/master/README.cn.md

MySQL 索引 详解(保姆级教程)

一、索引概述 索引是帮助 MySQL 高效获取数据的数据结构&#xff08;有序&#xff09;。在数据之外&#xff0c;数据库系统还维护着满足特定查找算法的数据结构&#xff0c;这些数据结构以某种方式引用&#xff08;指向&#xff09;数据&#xff0c;这样就可以在这些数据结构上…

面试热题(合并两个有序列表)

将两个升序链表合并为一个新的 升序 链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。 合并链表这类型题也是比较经典的题了&#xff0c;因为链表是由指针相互指向而确定位置&#xff0c;所以我们只需要改变某些节点的指针便可以做到对链表进行排序 今天这个方法…

【人工智能124种任务大集合】-集齐了自然语言处理(NLP),计算机视觉(CV),语音识别,多模态等任务

大家好&#xff0c;我是微学AI&#xff0c;今天给大家介绍一下人工智能124种任务大集合&#xff0c;任务集合主要包括4大类&#xff1a;自然语言处理&#xff08;NLP&#xff09;、计算机视觉&#xff08;CV&#xff09;、语音识别、多模态任务。 我这里整理了124种应用场景任…

代码审计-ASP.NET项目-未授权访问漏洞

代码审计必备知识点&#xff1a; 1、代码审计开始前准备&#xff1a; 环境搭建使用&#xff0c;工具插件安装使用&#xff0c;掌握各种漏洞原理及利用,代码开发类知识点。 2、代码审计前信息收集&#xff1a; 审计目标的程序名&#xff0c;版本&#xff0c;当前环境(系统,中间件…

词法分析器的设计与实现

1、实验目的及要求 1.1、实验目的 加深对词法分析器的工作过程的理解&#xff1b;加强对词法分析方法的掌握&#xff1b;能够采用一种编程语言实现简单的词法分析程序&#xff1b;能够使用自己编写的分析程序对简单的程序段进行词法分析。 1.2、实验要求 1&#xff09;对单词…

深入理解JVM之.intern()的用法

intern只在常量池里记录首次出现的实例引用 来看一段代码 public class RuntimeConstantPoolOOM {public static void main(String[] args) {String str1 new StringBuilder("计算机").append("软件").toString();System.out.println(str1.intern() st…

学习左耳听风栏目90天——第六天 6/90(学习左耳朵耗子的工匠精神,对技术的热爱)【如何拥有技术领导力】

学习左耳听风栏目90天——第六天 6/90&#xff08;学习左耳朵耗子的工匠精神&#xff0c;对技术的热爱&#xff09;【如何拥有技术领导力】

2022年下半年信息安全工程师下午真题及答案解析

试题一 (20分) 已知某公司网络环境结构主要由三个部分组成&#xff0c;分别是DMZ区、内网办公区和生产区&#xff0c;其拓扑结构如图1-1所示。信息安全部的王工正在按照等级保护2.0的要求对部分业务系统开展安全配置。图1-1当中&#xff0c;网站服务器的IP地址是192.168.70.14…

Leetcode-每日一题【剑指 Offer 29. 顺时针打印矩阵】

题目 输入一个矩阵&#xff0c;按照从外向里以顺时针的顺序依次打印出每一个数字。 示例 1&#xff1a; 输入&#xff1a;matrix [[1,2,3],[4,5,6],[7,8,9]]输出&#xff1a;[1,2,3,6,9,8,7,4,5] 示例 2&#xff1a; 输入&#xff1a;matrix [[1,2,3,4],[5,6,7,8],[9,10,11,…

向量数据库 Milvus Cloud Partition Key:租户数量多,单个租户数据少的三种解决方案

三种解决方案 这个问题提出的时候,Milvus 的最新版本是 2.2.8,我们做个角色互换,在当时站在这个用户的角度,留在我们面前的选择有这么几个: 为每个租户创建一个 collection 为每个租户创建一个 partition 创建一个租户名称的标量字段 接下来,我们依次分析下这三种方案的可…

刷了3个月的华为OD算法题,刷出感觉了,如洁柔般丝滑,文末送《漫画算法2:小灰的算法进阶》

目录 一、考研二战&#xff0c;入职华为&#xff0c;反向调剂电子科大深圳下面分享一道2023 B卷 朋友抽中题 简易内存池&#xff1a;二、题目描述三、输入描述四、输出描述样例&#xff1a;输出样例&#xff1a; 五、解题思路六、Java算法源码七、效果展示1、输入2、输出3、说明…

请解释一下CSS中的rem和em单位有什么不同,分别如何使用?

聚沙成塔每天进步一点点 ⭐ 专栏简介⭐ CSS中的rem和em单位的区别和使用⭐ em单位使用示例&#xff1a; ⭐ rem 单位使用示例&#xff1a; ⭐ 区别和适用场景⭐ 写在最后 ⭐ 专栏简介 前端入门之旅&#xff1a;探索Web开发的奇妙世界 记得点击上方或者右侧链接订阅本专栏哦 几何…

阿里云PolarDB数据库倚天ARM架构详细介绍

阿里云云原生数据库PolarDB MySQL版推出倚天ARM架构&#xff0c;倚天ARM架构规格相比X86架构规格最高降价45%&#xff0c;PolarDB针对自研倚天芯片&#xff0c;从芯片到数据库内核全链路优化&#xff0c;助力企业降本增效。基于阿里云自研的倚天服务器&#xff0c;同时在数据库…

PatchMatchNet 训练dtu数据集、训练曲线查看、实操教程图图文详解、

文章目录 1 查看要求 下载数据集2 训练2.1 路径配置2.2 训练2.3 模型输出 与 训练曲线查看2.4 输出训练 log文件1 查看要求 下载数据集 在代码文件加下打开 README.md文件找到训练说明,查看那要求、下载训练集、训练方法 ## Training Download pre-processed [DTUs trainin…

提升效率!Go语言开发者不可错过的必备工具集合!

&#x1f337;&#x1f341; 博主猫头虎 带您 Go to Golang Language.✨✨&#x1f341; &#x1f984; 博客首页——猫头虎的博客&#x1f390; &#x1f433;《面试题大全专栏》 文章图文并茂&#x1f995;生动形象&#x1f996;简单易学&#xff01;欢迎大家来踩踩~&#x1…