3个重要结论:
最小点覆盖数: 最小覆盖要求用最少的点(X集合或Y集合的都行)让每条边都至少和其中一个点关联。可以证明:最少的点(即覆盖数)=最大匹配数
最小路径覆盖=最小路径覆盖=|N|-最大匹配数
用尽量少的不相交简单路径覆盖有向无环图G的所有结点。解决此类问题可以建立一个二分图模型。把所有顶点i拆成两个:X结点集中的i和Y结点集中的i',如果有边i->j,则在二分图中引入边i->j',设二分图最大匹配为m,则结果就是n-m。
二分图最大独立集=顶点数-二分图最大匹配
在N个点的图G中选出m个点,使这m个点两两之间没有边,求m最大值。
如果图G满足二分图条件,则可以用二分图匹配来做.最大独立集点数 = N - 最大匹配数。
例题:
http://poj.org/problem?id=1469 COURSES
有了匈牙利算法的基础,该题就是一道非常简单的题目了:该题给出P门课程,N个学生,问能否从中选出P个学生,使每个学生上不同的课,且每个课程有一个学生。典型的二分图匹配的问题,我们只要计算最大二分图匹配数,如果和课程数相同就输出YES,否则输出NO。
//poj_1469 /*==================================================* | 二分图匹配(匈牙利算法DFS 实现) | INIT: g[][]邻接矩阵; | 优点:实现简洁容易理解,适用于稠密图,DFS找增广路快。 | 找一条增广路的复杂度为O(E),最多找V条增广路,故时间复杂度为O(VE) ==================================================*/ #include<stdio.h> #include<memory.h> bool g[110][310]; //邻接矩阵,true代表有边相连 bool flag,visit[310]; //记录V2中的某个点是否被搜索过 int match[310]; //记录与V2中的点匹配的点的编号 int p,n; //二分图中左边、右边集合中顶点的数目 // 匈牙利算法 bool dfs(int u) { for (int i = 1; i <= n; ++i) { if (g[u][i] && !visit[i]) //如果节点i与u相邻并且未被查找过 { visit[i] = true; //标记i为已查找过 if (match[i] == -1 || dfs(match[i])) //如果i未在前一个匹配M中,或者i在匹配M中,但是从与i相邻的节点出发可以有增广路径 { match[i] = u; //记录查找成功记录,更新匹配M(即“取反”) return true; //返回查找成功 } } } return false; } int main(void) { int i,j,k,t,v,ans; scanf("%d",&t); while (t--) { scanf("%d %d", &p, &n); for (i = 1; i <= p; i++) { for (j = 1; j <= n; j++) g[i][j] = false; } for (i = 1; i <= n; i++) match[i] = -1; flag = true; for (i = 1; i <= p; i++) { scanf("%d",&k); if (k == 0) flag = false; while (k--) { scanf("%d",&v); g[i][v] = true; } } if (flag) { ans = 0; for (i = 1; i <= p; i++) { memset(visit,false,sizeof(visit)); //清空上次搜索时的标记 if( dfs(i) ) //从节点i尝试扩展 ans++; } if (ans == p) puts("YES"); else puts("NO"); } else puts("NO"); } return 0; }