从书和其他一些博主那里零零散散学了一些关于匹配的东西
若有错误,还望斧正
1.二分图的匹配
我们的故事从二分图开始。
有这么一句话:在图论中,匹配是指两两没有公共点的边集。二分图最大匹配问题是这样的:给出一个二分图,找一个边数最大的匹配,即选出尽量多的边,使得任意两条选中的边均没有公共点。如果,这些边把所有的点都包括进去,则称这个匹配是完美匹配。
二分图是什么呢.
----> 设G=(V,E)是一个无向图,如果顶点V可分割为两个互不相交的子集(A,B),并且图中的每条边(i,j)所关联的两个顶点i和j分别属于这两个不同的顶点集(i in A,j in B),则称图G为一个二分图。 --------------这是我度娘上给出的定义
而简单一些的理解是:二分图(我们这里目前只讨论无向图,有向图的匹配问题和无向图差不多,无论是A->B,还是B->A,两者都可以匹配在一起,但具体问题具体分析),可以简单理解为此图中存在两个集合,分别称为X、Y。X中的点互相之间没有边,Y中的点互相也没有边。但X中的点和Y中的点可以有七七八八的边,将两边的点连接在了一起。
这里就会涉及到一个,二分图的判断问题。
---->可以采用涂色的方法。即我随便找一个点,涂成白色(数组中标为1),则和他有边的点涂成黑色(数组中标为2)。如此dfs下去。直到涂完最后一个点,当然在涂点的时候,还要判断是否他和已经涂上颜色的点的颜色不一样。若能清清楚楚地分成两种颜色,就说明这个图是一个二分图。
接下来判断玩二分图之后,我们就开始匹配了!
2.增广路定理+匈牙利算法
匈牙利算法的核心,就是找增广路。所以我们先来看看?增广路定理。
为了方便叙述,我们先来说几个概念。
匹配边:这条边所连接的两个点互相匹配。
未匹配边:这条边所连接的两个点不互相匹配。
未盖点:未匹配点,用于表示不与任何匹配边邻接的点,即还没有匹配上的点。而除了这些未盖点,其余都是匹配点。
交替路:从一个未盖点出发,依次经过非匹配边、匹配边、非匹配边······所得到的路径。
如若交替路的终点是一个未盖点,则称为这条交替路为一条增光路。所以增光路就是一条,起点是未盖点,终点是未盖点,且一次经过非匹配边、匹配边、非匹配边······的一条路。当然最后一条边一定是一条非匹配边。在增光路中,非匹配边比匹配边多一条!!!
增广路的作用是改进匹配。假设我们已经找到了一个匹配,如何判断这个匹配是不是最大匹配呢?
---->看增广路。如果在匹配的基础上能找到一条增广路,那只要我们把这条路上的匹配边和非匹配边相互交换,得到的匹配就会比刚才的匹配多一条边。反过来,如果我们找不到增光路,则当前的匹配就是最大匹配了。这就是增光路定理,即一个匹配是最大匹配的充分必要条件是不存在增广路(证明略,可见图论证明)。当然,这个充要条件适合于任意图,并不仅仅是二分图。
下面来说说匈牙利算法。
---->这里的匈牙利算法目前只涉及到没有权值的边(默认边的权值都为1)。
我们在写代码的时候,可以边连边找。即从一个未盖点出发,我们找一条边,如果这条边能成为一条匹配边,则直接连起来。要是这条边的另外一个点不是未盖点,没关系,我们先找其他的边,若可以成为匹配边,连起来,找下一个点。没有的话,我们就以这个点为那个起点的未盖点,然后找那个子图的增广路。
匈牙利算法(这个博主写的很易懂)。
int dfs(int x){
for (int i=0; i<m+1; i++){//Y中m个人
if (map[x][i] != 0 && vis[i] == 0){
vis[i] ++;
if (l[i] == 0 || dfs(l[i]){//l数组表示和i匹配了的那个点
l[i] = x;
return 1;
}
}
}
return 0;
}