首页 > 其他分享 >二分图

二分图

时间:2024-10-23 21:20:20浏览次数:6  
标签:二分 匹配 最大 增广 完美 右部点

二分图速通

定义

若一个无向图 \(G=(V,E)\) 的点集 \(V\) 可以分解成两个互不相交的子集 \(A,B\),且对于所有边 \((i,j)\) 的端点 \(i,j\) 都分别属于子集 \(A,B\) 中的元素,则称 \(G\) 是一个二分图。

判定

一张无向图是二分图,当且仅当图中不存在奇环。

故我们有染色算法判定二分图:BFS 将每个顶点的相邻点都染成不同的颜色,若相邻点有相同颜色,则说明不是二分图。否则是二分图。

相关定义

匹配独立边集:一张图中无公共点的边集合。

  • 极大匹配:无法再增加匹配边的匹配,不一定是最大匹配。
  • 最大匹配:匹配边数量最多的匹配,不一定唯一,但最大匹配的边数一定小于等于点数的一半。
  • 最大权匹配:带权图中,边权和最大的匹配。
  • 最大权最大匹配:所有最大匹配中边权和最大的匹配,即优先满足匹配边数量最多的前提下的最大权匹配。
  • 完美匹配完全匹配完备匹配:所有点都属于匹配。易得此时符合最大匹配。若图是完全图且边数为偶数,必然存在完美匹配。
  • 近完美匹配:点数为奇数的图中,除去一个点以外剩下的点符合完美匹配。

交错路:始于非匹配点且由匹配边和非匹配边交错而成的路径。

增广路:始于非匹配点、终于非匹配点的交错路。增广路中边的数量为奇数,且第一条边和最后一条边一定不属于匹配边。如果将增广路上的所有匹配边和非匹配边交换(取反),可以得到一个更大的匹配。

二分图最大匹配

核心思路

枚举所有未匹配点,找增广路,直到找不到增广路。

算法流程(匈牙利算法)

1965 年由匈牙利数学家 Edmonds 提出。

初始置 \(M\) 为空。每次找出一条增广路 \(P\),通过取反操作找出更大的匹配 \(M'\) 代替 \(M\),直到找不出增广路为止。时间复杂度 \(O(nm)\)。

具体地,每次考虑一个左部未匹配点,寻找一个右部点尝试与之匹配。一个右部点能被匹配当且仅当满足如下两条件之一:

  1. 该点未匹配。
    此时直接把两个点匹配。
  2. 该点之前匹配的左部点可以找到另一个右部点与之匹配。
    此时递归进入该左部点,为之寻找与之匹配的右部点。利用访问标记避免重复搜索。

实现(P3386 【模板】二分图最大匹配

#include<bits/stdc++.h>
#define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<20,stdin),p1==p2)?EOF:*p1++)
using namespace std;

char buf[1<<20],*p1=buf,*p2=buf;
int read(){
	int x=0;
	char ch=getchar();
	while(!isdigit(ch))ch=getchar();
	while(isdigit(ch))x=(x<<3)+(x<<1)+(ch^48),ch=getchar();
	return x;
}
constexpr int MAXN=1005;
int n,m,k,head[MAXN],tot;
struct{int v,to;}e[50005];
void addedge(int u,int v){
	e[++tot]={v,head[u]};
	head[u]=tot;
} 
int match[MAXN],ans;
bool vis[MAXN];

bool dfs(int u){
	for(int i=head[u];i;i=e[i].to){
		if(vis[e[i].v])continue;
		vis[e[i].v]=1;
		if(!match[e[i].v]||dfs(match[e[i].v]))
			return match[e[i].v]=u,1;
	}
	return 0;
}

int main(){
	n=read(),m=read(),k=read();
	for(int i=1,u,v;i<=k;++i){
		u=read(),v=read();
		addedge(u,v);
	}
	for(int i=1;i<=n;++i){
		memset(vis,0,sizeof(bool)*(n+m+5));
		ans+=dfs(i);
	}
	printf("%d\n",ans);
	return 0;
}

标签:二分,匹配,最大,增广,完美,右部点
From: https://www.cnblogs.com/laoshan-plus/p/18498392

相关文章

  • 二分图
    二分图概念假设\(G=(V,E)\)是一个无向图,若点集\(V\)可以分解成互不相交的子集\((A,B)\),并且图中所有边\((i,j)\)的端点\(i\)、\(j\)分别属于子集\(A\)、\(B\),则称\(G\)是一个二分图定理:一张无向图时二分图,当且仅当图中不存在奇环。染色法判定一个图是否是二分图......
  • 二分图学习笔记
    1.概念假设图\(G=(V,E)\)是无向图,若顶点集\(V\)可以分成两个互不相交的子集\((A,B)\),且任意边\((i,j)\)两端点分别属于两子集,则图\(G\)是二分图判断方法:染色法匹配:无公共点的边集匹配数:边集中边的个数最大匹配:匹配数最大的匹配增广路:设M是一个匹配,如果存在一条连接两个未匹......
  • 二分算法
    今天学了二分算法:在一个有序的列表里找一个数,用for循环,每次比较中间的数和要找的数,要找的数大则将头移到中间的数的下一个数,否则将尾移到中间的数。(头算尾不算)这是代码:#include<bits/stdc++.h>usingnamespacestd;inta[100001];intbs(inta[],intl,intr,intx){ i......
  • Dilworth 定理与二分图部分理论
    给定一个DAG,定义链:一条链内任意两点之间都存在一条路径反链:任意两点都不存在路径Dilworth定理:最长反链\(=\)最小链覆盖。最小链覆盖内一个点只能归属于一条链,但链不一定是连续的。事实上这个还能转化为“选出若干条(一般定义下的)链,但一个点可以在多条链内”,本质相同。......
  • P11217 【MX-S4-T1】「yyOI R2」youyou 的垃圾桶(线段树上二分)
    link赛时是想到普通的线段树+二分\(O(q\log^2n)\),预期是70pts,实际50pts后面发现又是在longlong类型的计算中,1ll写成了1,然后爆负数,复杂度就错了,T了四个点开题,读起来是一个很套路的题目要对区间在线修改,区间加、(区间乘?),发现数据很大,那就是线段树、树状数组维护了思......
  • 二分查找
    1.好处二分查找(折半查找)效率高,时间复杂度低,但是仅能用于有序数组2.代码及其逻辑二分查找的逻辑就是通过我们想要找到的值与中间量(mid)作比较,来不断缩小范围,如果说我们想要查找的值比中间量要大,那么我们就会取前半个区间,在进行一次与中间量的比较,不断的循环,就能找到我们想要查......
  • 二分求操作后的最大最小中位数
    这类题是让你求对序列进行一系列操作之后的最小/最大中位数求最小中位数二分最小中位数,显然二分要符合mid越大越对,边界才能向下收缩。对于这个条件,我们选择计算小于等于当前mid的数才是对的,因为这样显然mid越大cnt越大,而符合这个条件,我们就不断收缩上界,直到达到第......
  • Matlab使用LSTM或BiLSTM对一维信号(语音信号、心电信号等)进行二分类源程序。也可以改
     Matlab使用LSTM或BiLSTM对一维信号(语音信号、心电信号等)进行二分类源程序。也可以改成多分类。包含数据和代码,数据可以直接替换为自己的数据。如果用BiLSTM,程序中只需要把lstmlayer改为bilstmlayer即为BiLSTM网络,其他地方不需要任何改动。工作如下:1、加载数据集,一共为......
  • 茴香豆的茴有四种写法,那二分有几种写法?
    《编程珠玑》一书的作者JonBentley曾经说过:“90%的程序员无法正确实现二分查找算法...”,今天,本文将带领你会写二分。经典写法现在我们来求解这样一个通用的二分查找问题:有一个不下降序列$a$,我们要从其中所有找到大于等于$k$的数的最小的下标。boolcheck(intindex)......
  • 704.二分查找
    题目给定一个n个元素有序的(升序)整型数组nums和一个目标值target,写一个函数搜索nums中的target,如果目标值存在返回下标,否则返回-1。示例1:输入:nums=[-1,0,3,5,9,12],target=9输出:4解释:9出现在nums中并且下标为4示例2:输入:nums=[-1,0,3,......