二部图例题HDU-2063(匈牙利算法)
二部图基本概念:
- 二部图:一个图中的所有点能够被划分为两个集合,图中的所有边都跨越了集合的边界。(例如:一群人以男女区分为两部分,一些男生喜欢一些女生,一些女生喜欢一些男生,这些男女生和这些喜欢的情况可以称作二部图)
- 匹配:匹配是一组边的集合,其中任意两边都没有公共点。(若彼此喜欢男女生能够在一起,某一情况下所有这种能够在一起的关系称为匹配,这一情况下在一起的关系就称为匹配边,原本喜欢但是没有在一起的就称为未匹配边)
- 最大匹配:所有匹配中,边数最多的一个匹配关系。(能够使得最多对男女生在一起的一种情况)
- 完美匹配:一个图中所有顶点都是匹配点(所有男生刚好和所有女生彼此之间一一匹配的一种情况)
匈牙利算法:
交错路:从一个未匹配点出发,依次遍历未匹配边、匹配边、未匹配边、匹配边. . .交错着最后回到未匹配点的路径。
增广路径:起点和终点都是未匹配点的交错路径。增广路径的存在说明匹配数还能够增加。所以它才叫增广路径的吧
算法核心:对于一种匹配的情况,若能够找到它的一条增广路径(或者能够对这种匹配进行补充,这种情况直接更新就好了),说明这一情况下还有另外的一种情况使得匹配数更大。而这种更大匹配数的情况就是原本的匹配点与未匹配点交换的情况。即舍弃原本匹配的,改变为新的匹配(原本的未匹配)。
于是我们选择二部图中的一个部进行遍历,这个部中的点作为起始选择的未匹配点。判断目前的匹配情况下能否找到以这个点为起点的增广路径(或者这个点能够作为新的补充),如果可以就进行更新。直到这个部的所有起点都遍历完了。
为了祭奠这道题二部图匹配-HDU-2063-过山车
最后放上代码然后下班:
#include<iostream>
#include<stdio.h>
#include<vector>
#define Mx 10086
using namespace std;
//万事开头难
int match[Mx]; //match[i]表示第i个女生当前匹配的男生编号,0表示没有
vector<int>boys[Mx];//记录每个男生可能匹配到的女生
int vis[Mx]; //记录在这一次选择中被访问过的结点
int bn, gn, n;
/*dfs==true的条件是这个兄弟找到了匹配,
而且不会使得其他已经找到匹配的兄弟失去匹配,包含了对match的更新*/
bool dfs(int x) {
//细节转int
for (int i = 0; i < (int)boys[x].size(); i++) {
int g = boys[x][i];
if (vis[g] == 0) {
vis[g] = 1;
if (match[g] == 0 || dfs(match[g])) {
match[g] = x;
return true;
}
}
}
return false;
}
int main() {
while (scanf("%d", &n) && n && scanf("%d %d", &bn, &gn)) {
memset(match, 0, sizeof(match));
for (int i = 0; i < gn+1; i++) {
boys[i].clear();
}
for (int i = 0; i < n; i++) {
int a, b; //a为男生编号,b为女生编号
scanf("%d %d", &a, &b);
boys[a].push_back(b);
}
int ans = 0;
//选择男生部,作为起始的未匹配点进行遍历
for (int i = 1; i <= bn; i++) {
memset(vis, 0, sizeof(vis));
if (dfs(i)) {
ans++;
}
}
printf("%d\n", ans);
}
return 0;
}