二分图匹配
匹配:在图论中,一个「匹配」(matching)是一个边的集合,其中任意两条边都没有公共顶点。
无权图
匈牙利算法
#include<bits/stdc++.h>
using namespace std;
const int MAX = 10000;
vector<int> G[MAX];
int vis[MAX];
int link[MAX];//代表当前状态Y中与X相连的点(即d[y] = x)
int n, m;//n为X集合点数,m为Y集合点数(这里默认点的序号为X到Y依次递增)
int find(int t)//这一个t保证它是X中的点
{
for(int i = 0; i < G[t].size(); i++){//从Y中的每一点开始找
int tmp = G[t][i];//与t相连的tmp
if(!vis[tmp]){//如果这点没有被前面几次找过,
vis[tmp] = 1;
if(link[tmp] == -1 || find(link[tmp])){//这里寻找增广路径的结束条件就是找到Y中未被配对过的点,如果这点被配对过,那么就从这点配对的X中的点进行新一轮的can()
//第一个条件表明Y中的tmp还未和X中的某个点匹配起来,第二个条件理解为link[tmp]中存的之前X中的点是否还能找到其他可以匹配的点
link[tmp] = t;
return 1;
}
}
}
return 0;
}
int maxmatch()
{
int num = 0;
for(int i = 1; i <= n; i++){
memset(vis, 0, sizeof(vis));
if(can(i)){
num++;
}
}
return num;
}
int main()
{
while(scanf("%d %d", &n, &m) != EOF){
for(int i = 1; i <= n; i++)
G[i].clear();
memset(link, -1, sizeof(link));
int s;
scanf("%d", &s);
while(s--){
int a, b;//表示X中的a与Y中的b相连
scanf("%d %d", &a, &b);//假设输入的点X和Y分开输入(都是从1开始)
G[a].push_back(b+n);
G[b+n].push_back(a);//由于是无向图
}
printf("%d\n", maxmatch());
}
return 0;
}
最小覆盖
二分图的最小覆盖分为最小顶点覆盖和最小路径覆盖:
①最小顶点覆盖是指最少的顶点数使得二分图G中的每条边都至少与其中一个点相关联,二分图的最小顶点覆盖数=二分图的最大匹配数;
②最小边覆盖,是指用尽量少的不相交简单路径覆盖二分图中的所有顶点。二分图的最小路径覆盖数=|V|-二分图的最大匹配数;
最大独立集
最大独立集是指寻找一个点集,使得其中任意两点在图中无对应边。对于一般图来说,最大独立集是一个NP完全问题,对于二分图来说最大独立集=|V|-二分图的最大匹配数
最小路径覆盖(DAG)