当前位置:   article > 正文

二分图匹配

二分图匹配

定义:

  • 二分图:一个图被分成了两部分,相同的部分没有边

  • 匹配:二分图G的子图M中,M的边集{E}中的任意两条边都不指向同一个顶点

  • 极大匹配:在当前已完成的匹配下,无法再通过增加未完成匹配的边的方式来增加匹配的边数

  • 最大匹配:是所有极大匹配当中边数最大的一个匹配

  • 完全匹配(完备匹配):一个匹配中,图中的每个顶点都和图中某条边相关联

有什么用:

  • 定理1:最小点覆盖数 = 最大匹配数

    点覆盖:点集合使得任意一条边至少有一个端点在集合中

  • 定理2:最大独立集 = 顶点数 - 最大匹配数

    独立集:点集合中任何两个顶点都不互相连接

  • 定理3:最小路径覆盖数 = 顶点数 – 最大匹配数

    路径覆盖:任何一个点都属于且仅属于一条路径

代码实现:(匈牙利算法)
匈牙利算法与交错路

#include<iostream>
#include<vector>
#include<cstring>
using namespace std;
vector<int> g[1005];
int n,m,e;
int link[1005],cnt;
int vis[1005];
int find(int x){
   
    for(int i=0;i<g[x].size();i++){
   
        int u=g[x][i];
        if(!vis[u]){
   
            vis[u]=1;
            if(link[u]==0||find(link[u])){
   
                link[u]=x;
                return 1;
            }
        }
    }
    return 0;
}
int main(){
   
    cin>>n>>m>>e;
    int x,y;
    for(int i=1;i<=e;i++){
   
        cin>>x>>y;
        if (x>=1&&y>=1&&x<=n&&y<=m)
        	g[x].push_back(y);
    }
    for(int i=1;i<=n;i++){
   
        memset(vis,0,sizeof(vis));
        if(find(i)) cnt++;
    }
    cout<<cnt;
    return 0;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43

时间复杂度:

O(nm) 其中n是点数,m是边数

但事实上,对于绝大部分的二分图,匈牙利算法都跑不够上限

KM算法

题目:

最小点覆盖数:

定理证明:http://www.cnblogs.com/jasonlixuetao/p/4756026.html

POJ 3041

题意:有一个N*N的网格,该网格有K个障碍物.你有一把武器,每次你使用武器可以清楚该网格特定行或列的所有障碍.问你最少需要使用多少次武器能清除网格的所有障碍物?

/*把网格的行1到N看成左边点集的点,网格的列号看成右边点集的点
如果(i,j)格有障碍,那么就在左边i点到右边j点之间连接一条边
接下来求最小点覆盖数即可*/
#include<iostream>
#include<cstdio>
#include<cstring>
#include<vector>
using namespace std;
const int maxn=500+10;
int n;
vector<int> g[maxn];
int vis[maxn];
int link[maxn];
int find(int u) {
   
	for(int i=0;i<g[u].size();i++){
   
		int v=g[u][i];
		if(!vis[v]) {
   
			vis[v]=1;
			if(!link[v]||find(link[v])){
   
				link[v]=u;
				return 1;
			}
		}
	}
	return 0;
}
int main(){
   
	int n,k;
	scanf("%d%d",&n,&k);
	while(k--) {
   
		int u,v;
		scanf("%d%d",&u,&v);
		g[u].push_back(v); 
	}
	int ans=0;
	for(int i=1;i<=n;i++){
   
		memset(vis,0,sizeof(vis));
		if(find(i)) ans++;
	}
	printf("%d\n",ans);
	return 0;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
最大独立集:

定理证明:最大独立集=顶点数-最小顶点覆盖数=顶点数-最大匹配数

HDU 3829

题意:动物园有若干只狗和猫,每个小朋友都要么喜欢一只狗不喜欢一只猫,要么反过来。现在要移除一些狗和猫,小朋友只有在不移除自己喜欢的动物,移除了自己不喜欢的动物才会开心。问最多能让几个小朋友开心。

/*把人当作节点,矛盾的人连边,做最大独立集*/
#include<iostream>
#include<cstdio>
#include<cstring>
  • 1
  • 2
  • 3
  • 4
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/Gausst松鼠会/article/detail/64651
推荐阅读
相关标签
  

闽ICP备14008679号