图论中的难见就是建图然后套用算法。
特点:
只能一一对应,即XX只能有一个人。
先来一个比较好的入门资料二分图最大匹配 参考
算法的思路是不停的找增广路径, 并增加匹配的个数,增广路径顾名思义是指一条可以使匹配数变多的路径,在匹配问题中,增广路径的表现形式是一条”交错路径”,也就是说这条由图的边组成的路径, 它的第一条边是目前还没有参与匹配的,第二条边参与了匹配,第三条边没有..最后一条边没有参与匹配,并且始点和终点还没有被选择过。这样交错进行,显然他有奇数条边。那么对于这样一条路径,我们可以将第一条边改为已匹配,第二条边改为未匹配…以此类推。也就是将所有的边进行”反色”,容易发现这样修改以后,匹配仍然是合法的,但是匹配数增加了一对。另外,单独的一条连接两个未匹配点的边显然也是交错路径。可以证明。当不能再找到增广路径时,就得到了一个最大匹配,这也就是匈牙利算法的思路。
3个重要结论:
最小点覆盖数: 最小覆盖要求用最少的点(X集合或Y集合的都行)让每条边都至少和其中一个点关联。可以证明:最少的点(即覆盖数)=最大匹配数
最小路径覆盖=最小路径覆盖=|N|-最大匹配数
用尽量少的不相交简单路径覆盖有向无环图G的所有结点。解决此类问题可以建立一个二分图模型。把所有顶点i拆成两个:X结点集中的i和Y结点集中的i’,如果有边i->j,则在二分图中引入边i->j’,设二分图最大匹配为m,则结果就是n-m。
二分图最大独立集=顶点数-二分图最大匹配
在N个点的图G中选出m个点,使这m个点两两之间没有边,求m最大值。
如果图G满足二分图条件,则可以用二分图匹配来做.最大独立集点数 = N - 最大匹配数。
做题见过的几种建图方案:
1. 二维矩阵中,1X2的方格覆盖将图看成国际象棋那种黑白相间
2. 2015上海邀请赛热身题B看成一直黑白相间下去的二分图
3. 有向无环图,每条边相连的两点看成二分图的两部分
4. 二维矩阵中,每行每列 只能放一个,将X坐标集合看成一部分,Y看成一部分。交点有ship的时候对应的行和列才不可以放,就是说你选了对应的行,相当于对应的列也被选择。然后这不就是一种匹配吗,所以我们就可以根据这样的性质来建立二部图,从而转化成求二部图最大匹配的问题。
将横着的没有被阻挡的块合并成一个大块。将竖着的没有被阻挡的块合并成一个大块。 这样得到若干个横向块,和纵向块,如果一横向块与纵向块之间有共同的点,那么就将这两个大块连线(构造一个横向块与纵向块的邻接矩阵)。 构造好之后就可以算横向块与纵向块的最大匹配数。(HDU 5093 ZOJ 1654 ZOJ 3156)
5. 最小路径覆盖问题,原始的最小路径覆盖的各个路径是不能有相同的点的,如果是可是可相交的路径覆盖就要先求一次闭包。poj 2594 参考
模板
#include <stdio.h>
#include <string.h>
#define MX 155
int n, m;
bool g[MX][MX], v[MX];
int match[MX];
bool find(int x) {
for(int i = 1; i <= n; ++i) {
if(!v[i] && g[x][i]) {
v[i] = 1;
if(match[i] == -1 || find(match[i])) {
match[i] = x;
return 1;
}
}
}
return 0;
}
void hungary() {
int ans = 0;
for(int i = 1; i <= n; ++i) {
memset(v, 0, sizeof(v));
if(find(i)) ans ++;
}
printf("%d\n", n - ans);
}
int main() {
int cas;
scanf("%d", &cas);
while(cas --) {
while (scanf("%d%d", &n, &m) != EOF) {
memset(g, 0, sizeof(g));
memset(match, -1, sizeof(match));
int a, b;
for(int i = 1; i <= m; ++i) {
scanf("%d%d", &a, &b);
g[a][b] = 1;
}
hungary();
}
}
return 0;
}
原文地址:http://blog.csdn.net/gg_gogoing/article/details/46341859