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