• 二分图全家桶


    定义

    顶点可以分成(A,B)两个集合,每条边的两个顶点分别位于(A,B)集合中的图

    以该图为例,标记黄色顶点属于集合(A),灰色顶点属于集合(B),则所有边的两个顶点分属于(A,B)集合,该图是一张二分图

    二分图中不含奇环(不含奇环的图都是二分图)

    判定

    黑白染色:用(DFS)对原图的顶点进行染色,若某一点为黑色,则与其相邻的点全部染为白色,如果染色过程中不出现矛盾,则原图是二分图

    证明:黑白染色过程中出现矛盾,当且仅当图中存在奇环

    常见二分图模型

    相邻两点冲突

    这类题目有些图论模型是需要自己建立的

    洛谷P1330 封锁阳光大学

    洛谷P3430 [POI2005]DWU-Double-row

    棋盘问题

    棋盘通常可以黑白染色

    二分图相关问题

    二分图最大匹配

    匹配:

    任意两条边都没有公共点的一个边的集合称为二分图的一个匹配

    交错路:

    对于原图中的一条路径,存在奇数条边属于匹配,偶数条边不属于匹配,或相反的情况,那么这条路径被称为交错路

    增广路:

    对于图中任意一个匹配,如果原图存在一条长度为奇数的路径,满足路径的第奇数条边不属于该匹配,第偶数条边属于该匹配,那么这条路径被称为增广路

    最大匹配:

    边数最多的匹配 (不存在增广路的匹配)

    如图,加粗的黑边即是二分图的一个最大匹配

    匈牙利算法:

    二分图中常见的寻找最大匹配的算法

    其本质是贪心的从每个左部节点((A)集合节点)寻找增广路的过程

    依次考虑每个左部节点,找到一个右部节点与其匹配

    一个右部节点能与其匹配,必须满足一下两个条件之一:

    (1.)该节点尚未与其他左部节点匹配

    (2.)从该右部节点匹配的左部节点出发,寻找新的尚未标记的右部节点与其匹配

    条件一不用多解释,可以发现条件二就是在寻找增广路

    展开查看
    
    ```cpp
    #include
    #include
    #include
    #include
    #include
    using namespace std;
    namespace red{
    #define eps (1e-8)
    	inline int read()
    	{
    		int x=0;char ch,f=1;
    		for(ch=getchar();(ch<'0'||ch>'9')&&ch!='-';ch=getchar());
    		if(ch=='-') f=0,ch=getchar();
    		while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}
    		return f?x:-x;
    	}
    	const int N=1010;
    	int n,m,e,ret,tim;
    	int vis[N<<1],f[N<<1];
    	int head[N],cnt;
    	struct point
    	{
    		int nxt,to;
    		point(){}
    		point(const int &nxt,const int &to):nxt(nxt),to(to){}
    	}a[N*N];
    	inline void link(int x,int y)
    	{
    		a[++cnt]=(point){head[x],y};head[x]=cnt;
    	}
    	inline bool find(int x)
    	{
    		for(int i=head[x];i;i=a[i].nxt)
    		{
    			int t=a[i].to;
    			if(vis[t]==tim) continue;
    			vis[t]=tim;
    			if(!f[t]||find(f[t]))
    			{
    				f[t]=x;
    				return 1;
    			}
    		}
    		return 0;
    	}
    	inline void main()
    	{
    		n=read(),m=read(),e=read();
    		for(int x,y,i=1;i<=e;++i)
    		{
    			x=read(),y=read();
    			if(x>n||y>m) continue;
    			link(x,y+n);
    		}
    		for(int i=1;i<=n;++i)
    		{
    			++tim;
    			ret+=find(i);
    		}
    		printf("%d
    ",ret);
    	}
    }
    signed main()
    {
    	red::main();
    return 0;
    }
    ```
    

    例题:

    POJ2466 棋盘覆盖

    洛谷P1129 [ZJOI2007]矩阵游戏

    BZOJ 4950

    BZOJ1443 [JSOI2009]游戏Game

    二分图最小点覆盖

    图的覆盖:

    满足每一条边都有至少一个点在其中的点集,叫做图的覆盖

    最小覆盖:

    包含点数最少的覆盖

    最小覆盖=最大匹配(数值上)

    构造:

    先求出最大匹配,然后从右部节点的每一个未匹配点寻找交错路,并标记访问过的节点

    则左部标记节点和右部未标记节点构成一组最小覆盖

    证明:

    最小性:

    右侧所有未匹配点都被标记,左侧所有未匹配点都未被标记,所以所有覆盖都从匹配点中选择

    对于某一联通子图,左部匹配点被选择后,右侧一定不被选择,右侧匹配点被选择后左侧一定不被选择,所以最小覆盖=最大匹配

    合法性:

    一对匹配点一定同时被标记或未被标记,所以所有匹配边一定被覆盖

    连接左部匹配点和右部非匹配点的边会被左部覆盖

    连接右部匹配点和左部非匹配点的边会被右部覆盖

    最大匹配中不存在连接一对非匹配点的边

    所以合法性成立

    例题:

    POJ1325

    POJ2226

    二分图最大独立集

    图的独立集:

    任意两点在图中没有边相连的点集

    二分图最大独立集

    点数最多的二分图的独立集

    二分图最大独立集=图的点数-二分图最大匹配

    可以理解为图中所有点减去最少的点令剩下的点没有边相连,也就是用最少的点覆盖所有的边,即最小点覆盖

    例题:

    洛谷P2423 [HEOI2012]朋友圈

    二分图最小路径覆盖

    最小路径覆盖:

    用尽量少的不相交的简单路径覆盖有向无环图的所有节点

    最小路径覆盖=节点数-最大匹配

    构造:

    把原图中每个点拆成二分图中左右两个点,对于每条有向边((u,v)),从(u)的左部点向(v)的右部点连一条有向边,然后求最大匹配,用节点数减去

    证明:

    在边数(=0)时,显然需要节点数条路径

    那么对于每成功匹配二分图中的一对节点,代表某两个点可以通过一条路径连接,使路径覆盖数(-1)

    而最小路径覆盖中要求满足每个点入度和出读不超过(1),满足二分图最大匹配中的匹配边没有公共端点

    所以最小路径覆盖条数=节点数-最大匹配。

    例题:

    POJ1422

    可重叠最小路径覆盖

    考虑一条交叉路径(u-v-w)(x-v-y),这里(v)被两条路径覆盖了

    如果我们添加一条边(x-y),那么相当与(u-v-w)(x-y)的不可重叠最小路径覆盖

    这个东西我好像在考场上口胡过然后爆零了ddd

    如果我们把所有可以达到的点之间连一条边,就可以解决可重叠最小路径覆盖问题

    传递闭包我们可以选择floyd解决

    可重叠最小路径覆盖=floyd传递闭包+不可重叠最小路径覆盖

    POJ2594

    二分图最优匹配

    最优匹配:

    二分图每条边都有权值,权值和最大的匹配称为二分图最优匹配

    完美匹配:

    左部或者右部点集中所有点都被匹配

    顶标:

    给每个节点一个标号,记左部节点为(a_i),右部节点为(b_i),称为顶标,对于二分图任意一条边((u,v)),满足(a_u+b_vge val(u,v))

    相等子图:

    二分图中所有满足(a_u+b_v=val(u,v))构成的子图

    性质:

    相等子图的完美匹配就是二分图的最优匹配

    对于二分图的任意一个匹配,如果它属于相等子图,那么其边权和等于节点顶标和

    如果它不属于相等子图,那么其边权和le 节点顶标和

    因此相等子图的完美匹配就是二分图最优匹配

    KM算法

    放到模板题目里面讲UOJ80

    例题

    好像大部分都可以用费用流莽的样子……

    POJ3565

    稳定婚姻问题

    (n)个男生和(n)个女生要组成(n)对配偶,每个男生按照喜欢程度给女生排序,女生按照喜欢程度给男生排序

    如果存在两对配偶((A,a))((B,b))(A)(b)的喜欢程度比(a)高,(b)(A)的喜欢程度比(B)高,那么称这个婚姻系统是不稳定的

    如何求一个稳定的完美匹配?

    延时认可算法

    初始时刻所有男生都处于未匹配状态

    对于每个未匹配的男生,在所有未拒绝过他的女生里面选择他最喜欢的一个作为匹配

    每个女生在所有选择他的男生里面选择最喜欢的一个作为匹配(如果以前有匹配可以绿掉,让以前的匹配变成未匹配状态)

    直到所有男生找到妹子

    HDU1522 板子懒得放了

    大概结束了吧,这里的例题都偏入门然而作者太菜了也写不动难题

  • 相关阅读:
    iOS
    UIView
    sql server 无法创建索引 因为对象名称和索引名称重复
    select2多选
    NPOI 给导出Excel添加简单样式
    NPOI简单的给某个单元格字体设置颜色
    ASP.NET MVC5 历史数据查询
    C# 反射Reflection
    C# 程序集Assembly
    GetExecutingAssembly() 和 GetCallingAssembly() 的区别
  • 原文地址:https://www.cnblogs.com/knife-rose/p/12088704.html
Copyright © 2020-2023  润新知