图论:匹配与覆盖+独立集 团与支配集

计算机算法里面有:二分图匹配算法。将节点划分到两个集合,两边之间的点连线生成边。
    匹配:指的是无向图的边集的一个子集,使得这个子集中的任意两条边没有公共顶点且不包含自环。
        如果一个匹配不是其他匹配的子集,那么称这个匹配为极大匹配。在极大匹配中添加任意一条其他的
    边生成的集合都不是匹配。
    
    顶点覆盖:是指无向图的点集的一个子集,使得边集中的任意一条边都至少有一个端点在这个子集中。
    顶点覆盖的大小即为 顶点覆盖中的点的个数。
        如果其他的顶点覆盖都不是这个顶点覆盖的子集,则称这个顶点覆盖为:极小顶点覆盖。
    同理,可以推出边覆盖的定义。
    
    1.任意一个顶点覆盖的补集,一定是一个独立集。反之亦然。
    2.最小顶点覆盖+最大独立集 = V
    3.最大匹配中的所有端点组成的点集是一个顶点覆盖。
    4.在二分图中,最小顶点覆盖和最大匹配在数值上相等

独立集:是指无向图中点集的一个子集,其中任意两个点不相邻(即:没有变将他们连到一起)。不会存在某一条边

可以连接独立集中的两个点。等价于: 任意一条边最多有一个端点在独立集里。

最大的独立集称为:最大独立集。

团:与独立集的定义相对,团是指无向图中点集的一个子集,其中任意两点都有边连接。最大的团成为最大团。

支配集:是指无向图中点集的一个子集,所有无向图中的点,要么属于这个子集,要么与这个子集中的点相邻。

最小的支配集称为最小支配集。

     1.一个极大独立集一定是一个支配集。

     2.最小支配集不一定是独立集,但最小支配集的大小必然小于等于最小的极大独立集的大小。

     3.图G的最大团 = 图G的补图的最大独立集。

     4.最小顶点覆盖+最大独立集 = V

例题:hihocoder #1127 : 二分图三·二分图最小点覆盖和最大独立集

输入

第1行:2个正整数,N,M(N表示点数 2≤N≤1,000,M表示边数1≤M≤5,000)
第2..M+1行:每行两个整数u,v,表示一条无向边(u,v)

输出

第1行:1个整数,表示最小点覆盖数
第2行:1个整数,表示最大独立集数

样例输入
5 4
3 2
1 3
5 4
1 5
样例输出
2
3

代码:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <ctype.h>
#include <math.h>
#include <deque>
#include <algorithm>
#define eps 1e-8
#define N 1010

using namespace std;

int n, m;
int g[N][N];
int link[N];
bool vis[N];

int dfs(int dd)
{
	for(int i=1; i<=n; i++){
		if(!vis[i] && g[dd][i]==1 )
		{
			vis[i]=true;
			if(link[i]==-1 || dfs(link[i]) ){
				link[i]=dd;
				return 1;
			}
		}
	}
	return 0;
}

int main()
{
	scanf("%d %d", &n, &m);

	int i, j; int u,v;
	memset(g, 0, sizeof(g));
	memset(link, -1, sizeof(link));

	for(i=0; i<m; i++)
	{
		scanf("%d %d", &u, &v);
		g[u][v]=1; g[v][u]=1; //建立双向边
	}
	int cnt=0;
	for(i=1; i<=n; i++){
		memset(vis, false, sizeof(vis));
		cnt+=dfs(i);
	}
	int ans1=cnt/2; //最小点覆盖=最大匹配数
	int ans2=n-ans1; //最大独立集=V-最小点覆盖
	printf("%d
%d
", ans1, ans2 );

    return 0;
}
原文地址:https://www.cnblogs.com/yspworld/p/4672440.html