图论中的难见就是建图然后套用算法。
特点:
仅仅能一一相应,即XX仅仅能有一个人。
先来一个比較好的入门资料二分图最大匹配 參考 二分图建图方法
算法的思路是不停的找增广路径, 并添加匹配的个数,增广路径顾名思义是指一条能够使匹配数变多的路径,在匹配问题中,增广路径的表现形式是一条”交错路径”,也就是说这条由图的边组成的路径。 它的第一条边是眼下还没有參与匹配的,第二条边參与了匹配。第三条边没有..最后一条边没有參与匹配,而且始点和终点还没有被选择过。这样交错进行,显然他有奇数条边。
那么对于这样一条路径,我们能够将第一条边改为已匹配。第二条边改为未匹配…以此类推。
也就是将全部的边进行”反色”,easy发现这样改动以后,匹配仍然是合法的,但是匹配数添加了一对。另外。单独的一条连接两个未匹配点的边显然也是交错路径。能够证明。当不能再找到增广路径时,就得到了一个最大匹配,这也就是匈牙利算法的思路。
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 - 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;
}