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

计算机算法里面有:二分图匹配算法。将节点划分到两个集合,两边之间的点连线生成边。
    匹配:指的是无向图的边集的一个子集,使得这个子集中的任意两条边没有公共顶点且不包含自环。
        如果一个匹配不是其他匹配的子集,那么称这个匹配为极大匹配。在极大匹配中添加任意一条其他的
    边生成的集合都不是匹配。
    
    顶点覆盖:是指无向图的点集的一个子集,使得边集中的任意一条边都至少有一个端点在这个子集中。
    顶点覆盖的大小即为 顶点覆盖中的点的个数。
        如果其他的顶点覆盖都不是这个顶点覆盖的子集,则称这个顶点覆盖为:极小顶点覆盖。
    同理,可以推出边覆盖的定义。
    
    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\n%d\n", ans1, ans2 );



    return 0;

}

 

你可能感兴趣的:(图论)