【第二十四课】二分图:acwing-860染色法判定二分图 / acwing-861二分图的最大匹配 ( c++代码 )

本文主要是介绍【第二十四课】二分图:acwing-860染色法判定二分图 / acwing-861二分图的最大匹配 ( c++代码 ),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

目录

二分图是什么 

acwing-860染色法判定二分图

染色法

代码

acwing-861二分图的最大匹配

思路

代码


 

二分图是什么 

学习二分图的目的就是一些题目可以简化成二分图的模型来求解。 

二分图也就是:一个无向图顶点集,分成了两堆顶点(可以理解为两种不同性质),图中的每条边的两个端点分别属于两个不同的顶点集合这两个顶点集内部顶点之间没有边,所有的边都是连接两个不同顶点集合内的顶点

一个图是二分图当且仅当它不包含奇环图。(这句话正反都成立。

奇环图就是存在:边数是奇数的环 的图。

正向解释:假设存在一个奇数长度的环,那么环上的节点一定是交替属于两个集合,由于环的长度是奇数,环的最后一个节点又必须与环的起始节点相连,且它们属于同一个集合,这与二分图的定义相矛盾。因此,如果图是二分图,则不可能存在奇数长度的环

反之:如果一个图不包含奇环,那么我们通过染色法(后面会说)遍历图中的每一个节点,相邻两个节点染色不同,如果最终没有发生染色冲突的情况(即相邻的节点被染成了相同的颜色),那么就证明该图是二分图。

acwing-860染色法判定二分图

染色法

上面简单提过,其实叫染色法也只是一种标记而已,不用想的太复杂。

我们遍历图中的每个节点,将其染色,由于一个点染色之后,与其相直连的其他顶点应该染什么色应该是固定的,对吧?因为二分图的定义嘛:如果这个点还没被染色,就染成与该点不同的颜色,如果已经被染过色,就判断所染的颜色是否与该点的颜色相同。 如果发现有冲突,就说明不是二分图,直接跳出循环。

我们这里采用深度优先遍历,递归地对节点及其相邻节点进行染色,并且检查相邻节点是否与当前节点的颜色相同

代码

#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
const int N=1e5+10,M=2e5+10;
int n,m;
int h[N],e[M],ne[M],idx;
int color[N];//用俩标记是否被染色
void add(int x,int y)
{e[idx]=y;ne[idx]=h[x];h[x]=idx++;
}
bool dfs(int u,int c)//c表示该点被染的颜色
{color[u]=c;for(int i=h[u];i!=-1;i=ne[i]){int j=e[i];if(!color[j]){if(!dfs(j,3-c))return 0;}else if(color[j]==c)return 0;}return 1;
}
int main()
{cin>>n>>m;memset(h,-1,sizeof h);while(m--){int u,v;cin>>u>>v;add(u,v);//无向图add(v,u);}bool flag=1;//作为标记for(int i=1;i<=n;i++)//遍历所有顶点{if(!color[i])//如果该点没有被染色{if(!dfs(i,1))//就通过dfs将其染色,并判断染色是否存在冲突{flag=0;break;}}}if(flag)puts("Yes");else puts("No");return 0;
}

3-c作为染色,是因为我们这里用1 2分别表示染成的两种不同的颜色,而3-c刚好能够得到与前一个点的c不同的颜色。

acwing-861二分图的最大匹配

思路

首先要搞清楚匹配的概念:

可以直白地理解为:最多能有几对 一对一 的边

为了尽可能的得到最大的匹配数,有增广路径的概念,嗯,,

我这里按照图中说一下:比如1号点最开始应该直接匹配的是4号点,但是在对3号点进行匹配的时候,我们发现3号点只能与1号点匹配,于是我们就想让1号点再找找有没有其他可以选择的(3号点只有1号,只好让1号点变一变啦),发现1号点还可以与6号点匹配,那这样就皆大欢喜啦,我们多了一个匹配数。如果1号点也只有4号点能匹配,那最大匹配数就只有2啦。

所以我们这里的思路就是,只看左侧顶点,寻找可以与其匹配的右侧顶点。注意每次开始针对一个左侧顶点寻找之前,先把右侧顶点的标记都初始化一下,避免与之前的标记混淆。

find函数的主要思路就是,遍历这个左侧顶点直连的右侧顶点,观察其是否已经被访问过。未被访问的情况下:我们尝试为其寻找匹配的左侧顶点。[注意这里的思路是:为右侧顶点寻找可以匹配的左侧顶点]

有两种可能的情况:①该右侧顶点未被匹配过  ②该右侧顶点已经在前面几轮被匹配过了,名花有主了

-

①如果右侧顶点 j 尚未匹配(即 match[j] == 0),那么我们直接将其匹配给当前左侧顶点 x,并返回 1。

-

②如果右侧顶点 j 已经匹配了一个左侧顶点 y(即 match[j] 不为 0),我们需要尝试找到另一个左侧顶点与右侧顶点 j 匹配(递归调用)

为了实现上述所说的处理冲突以得到更大的匹配数的目的,我们定义match数组,其下标表示右侧顶点,数组存储的是右侧顶点所对的左侧顶点,当遇到了所谓的“冲突”,我们就再找找该右侧顶点所对的左侧顶点是否还有其他的顶点可以匹配

代码

#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
const int N=510,M=1e5+10;
int n1,n2,m;
int h[N],e[M],ne[M],idx;//由于我们只考虑左侧的点,因此采用邻接表存储是合理的
int match[N];//记录右侧顶点匹配的左侧顶点编号:下标表示右侧顶点 match数组表示的是左侧顶点
bool st[N];//标记右侧顶点是否已经被访问
void add(int u,int v)
{e[idx]=v;ne[idx]=h[u];h[u]=idx++;
}
bool find(int x)
{for(int i=h[x];i!=-1;i=ne[i]){int j=e[i];if(!st[j])//先检查右侧顶点 j 在这一轮中是否被访问过{st[j]=1;if(match[j]==0 || find(match[j])){match[j]=x;return 1;}}}return 0;
}
int main()
{cin>>n1>>n2>>m;memset(h,-1,sizeof h);while(m--){int u,v;cin>>u>>v;add(u,v);//因为只需要遍历左侧顶点}int res=0;for(int i=1;i<=n1;i++)//遍历左侧节点{memset(st,0,sizeof st);//以便重新标记每个右侧顶点的访问状态,不会受到之前搜索状态的影响if(find(i))res++;}cout<<res;return 0;
}

上面思路明白之后代码应该不难理解。 


写到这里。感觉时间好像有点紧😂。。嗯,,,

有问题欢迎指出,一起加油!!!

这篇关于【第二十四课】二分图:acwing-860染色法判定二分图 / acwing-861二分图的最大匹配 ( c++代码 )的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/715870

相关文章

【C++ Primer Plus习题】13.4

大家好,这里是国中之林! ❥前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不住分享一下给大家。点击跳转到网站。有兴趣的可以点点进去看看← 问题: 解答: main.cpp #include <iostream>#include "port.h"int main() {Port p1;Port p2("Abc", "Bcc", 30);std::cout <<

hdu2241(二分+合并数组)

题意:判断是否存在a+b+c = x,a,b,c分别属于集合A,B,C 如果用暴力会超时,所以这里用到了数组合并,将b,c数组合并成d,d数组存的是b,c数组元素的和,然后对d数组进行二分就可以了 代码如下(附注释): #include<iostream>#include<algorithm>#include<cstring>#include<stack>#include<que

hdu2289(简单二分)

虽说是简单二分,但是我还是wa死了  题意:已知圆台的体积,求高度 首先要知道圆台体积怎么求:设上下底的半径分别为r1,r2,高为h,V = PI*(r1*r1+r1*r2+r2*r2)*h/3 然后以h进行二分 代码如下: #include<iostream>#include<algorithm>#include<cstring>#include<stack>#includ

C++包装器

包装器 在 C++ 中,“包装器”通常指的是一种设计模式或编程技巧,用于封装其他代码或对象,使其更易于使用、管理或扩展。包装器的概念在编程中非常普遍,可以用于函数、类、库等多个方面。下面是几个常见的 “包装器” 类型: 1. 函数包装器 函数包装器用于封装一个或多个函数,使其接口更统一或更便于调用。例如,std::function 是一个通用的函数包装器,它可以存储任意可调用对象(函数、函数

C++11第三弹:lambda表达式 | 新的类功能 | 模板的可变参数

🌈个人主页: 南桥几晴秋 🌈C++专栏: 南桥谈C++ 🌈C语言专栏: C语言学习系列 🌈Linux学习专栏: 南桥谈Linux 🌈数据结构学习专栏: 数据结构杂谈 🌈数据库学习专栏: 南桥谈MySQL 🌈Qt学习专栏: 南桥谈Qt 🌈菜鸡代码练习: 练习随想记录 🌈git学习: 南桥谈Git 🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈�

【C++】_list常用方法解析及模拟实现

相信自己的力量,只要对自己始终保持信心,尽自己最大努力去完成任何事,就算事情最终结果是失败了,努力了也不留遗憾。💓💓💓 目录   ✨说在前面 🍋知识点一:什么是list? •🌰1.list的定义 •🌰2.list的基本特性 •🌰3.常用接口介绍 🍋知识点二:list常用接口 •🌰1.默认成员函数 🔥构造函数(⭐) 🔥析构函数 •🌰2.list对象

【Prometheus】PromQL向量匹配实现不同标签的向量数据进行运算

✨✨ 欢迎大家来到景天科技苑✨✨ 🎈🎈 养成好习惯,先赞后看哦~🎈🎈 🏆 作者简介:景天科技苑 🏆《头衔》:大厂架构师,华为云开发者社区专家博主,阿里云开发者社区专家博主,CSDN全栈领域优质创作者,掘金优秀博主,51CTO博客专家等。 🏆《博客》:Python全栈,前后端开发,小程序开发,人工智能,js逆向,App逆向,网络系统安全,数据分析,Django,fastapi

活用c4d官方开发文档查询代码

当你问AI助手比如豆包,如何用python禁止掉xpresso标签时候,它会提示到 这时候要用到两个东西。https://developers.maxon.net/论坛搜索和开发文档 比如这里我就在官方找到正确的id描述 然后我就把参数标签换过来

06 C++Lambda表达式

lambda表达式的定义 没有显式模版形参的lambda表达式 [捕获] 前属性 (形参列表) 说明符 异常 后属性 尾随类型 约束 {函数体} 有显式模版形参的lambda表达式 [捕获] <模版形参> 模版约束 前属性 (形参列表) 说明符 异常 后属性 尾随类型 约束 {函数体} 含义 捕获:包含零个或者多个捕获符的逗号分隔列表 模板形参:用于泛型lambda提供个模板形参的名

poj 1258 Agri-Net(最小生成树模板代码)

感觉用这题来当模板更适合。 题意就是给你邻接矩阵求最小生成树啦。~ prim代码:效率很高。172k...0ms。 #include<stdio.h>#include<algorithm>using namespace std;const int MaxN = 101;const int INF = 0x3f3f3f3f;int g[MaxN][MaxN];int n