二分匹配:二分图的一些性质
二分图又称作二部图,是图论中的一种特殊模型。 设G=(V,E)是一个无向图,如果顶点V可分割为两个互不相交的子集(A,B),并且图中的每条边(i,j)所关联的两个顶点i和j分别属于这两个不同的顶点集(i in A,j in B),则称图G为一个二分图。
1。一个二分图中的最大匹配数等于这个图中的最小点覆盖数
König定理是一个二分图中很重要的定理,它的意思是,一个二分图中的最大匹配数等于这个图中的最小点覆盖数。如果你还不知道什么是最小点覆盖,我也在这里说一下:假如选了一个点就相当于覆盖了以它为端点的所有边,你需要选择最少的点来覆盖所有的边。
2。最小路径覆盖=最小路径覆盖=|G|-最大匹配数 在一个N*N的有向图中,路径覆盖就是在图中找一些路经,使之覆盖了图中的所有顶点, 且任何一个顶点有且只有一条路径与之关联;(如果把这些路径中的每条路径从它的起始点走到它的终点, 那么恰好可以经过图中的每个顶点一次且仅一次);如果不考虑图中存在回路,那么每每条路径就是一个弱连通子集.
由上面可以得出:
1.一个单独的顶点是一条路径; 2.如果存在一路径p1,p2,......pk,其中p1 为起点,pk为终点,那么在覆盖图中,顶点p1,p2,......pk不再与其它的 顶点之间存在有向边.
最小路径覆盖就是找出最小的路径条数,使之成为G的一个路径覆盖.
路径覆盖与二分图匹配的关系:最小路径覆盖=|G|-最大匹配数;
3。二分图最大独立集=顶点数-二分图最大匹配
独立集:图中任意两个顶点都不相连的顶点集合。
二分图判定:染色判定法
直接利用题目HDU 2444 The Accomodation of Students
题意:给定n个学生,他们之间可能互相认识,首先判断能不能将这些学生分为两组,使组内学生不认识;
现想将学生两两分组,且保证每一组的学生都认识,这样分组可达到的最大组数为多大?
二分图判定+二分图最大匹配 直接看代码
#include <map> #include <set> #include <list> #include <cmath> #include <ctime> #include <deque> #include <stack> #include <queue> #include <cctype> #include <cstdio> #include <string> #include <vector> #include <climits> #include <cstdlib> #include <cstring> #include <iostream> #include <algorithm> #define LL long long #define PI 3.1415926535897932626 using namespace std; int gcd(int a, int b) {return a % b == 0 ? b : gcd(b, a % b);} const int MAXN = 410; const int MAXM = MAXN * MAXN * 2; const int INF = 0x3f3f3f3f; struct Edge { int u,v,next; int w; }edge[MAXM]; int head[MAXN],tot; void init() { tot = 0; memset(head,-1,sizeof(head)); } void add_edge(int u,int v,int w) { edge[tot].u = u; edge[tot].v = v; edge[tot].w = w; edge[tot].next = head[u]; head[u] = tot++; } bool used[MAXN]; int linker[MAXN],N,M; int color[MAXN]; bool bipartite(int u) { for (int i = head[u] ; i != -1 ; i = edge[i].next) { int v = edge[i].v; if (color[v] == color[u]) return false; if (!color[v]) { color[v] = 3 - color[u]; if (!bipartite(v)) return false; } } return true; } bool dfs(int u) { for (int i = head[u]; i != -1 ; i = edge[i].next) { int v = edge[i].v; if (!used[v]) { used[v] = true; if (linker[v] == -1 || dfs(linker[v])) { linker[v] = u; return true; } } } return false; } int calcu() { memset(linker,-1,sizeof(linker)); int ret = 0; for (int i = 1 ; i <= N ; i++) { memset(used,false,sizeof(used)); if (dfs(i)) ret++; } return ret; } int main() { while (scanf("%d%d",&N,&M) != EOF) { init(); memset(color,0,sizeof(color)); for (int i = 0 ; i < M ; i++) { int u,v; scanf("%d%d",&u,&v); add_edge(u,v,9797); // add_edge(v,u,9797); } bool flag = false; for (int i = 1 ; i <= N ; i++) { if (color[i] == 0) { color[i] = 1; if (!bipartite(i)) { flag = true; break; } } } if (!flag) { printf("%d\n",calcu()); } else puts("No"); } return 0; }