您的位置:首页 > 其它

hdu1054 匈牙利算法(增广路) (附匈牙利算法模板)

2014-02-06 15:14 281 查看
嗯。。。。今天开始写博客。。。。大一过去一半了。。。希望下半年能有个好的开始吧

先贴上百度百科里面对匈牙利算法的描述

算法轮廓:

⑴置M(这里M是图的一个子边集, 也就是现在要求的最大匹配的边集)为空

⑵找出一条增广路径P,通过异或操作获得更大的匹配M’代替M

⑶重复⑵操作直到找不出增广路径为止

而在代码的实现中,我们考虑枚举二分图左边点集中的点x的所有出边指向的点y,若y之前没有被匹配,那么(x,y)就是一对可以的匹配,我们便

将匹配数+1,。否则,我们便考虑给算法中已经于y匹配的点x'另找一个匹配,如果这时我们给x'找到了另外的匹配,那么(x,y)便可以成为一对行

的匹配。给x'寻找匹配的过程我们可以用dfs解决。从而我们有了解决最大匹配的方法。

下面给出我的模板

vector<int> v[]; //储存边的邻接表
int pre[]; // pre[i]记录与i匹配的左边点集中的点
bool flag[]; //记录是否访问过某一个点

bool find(int x) {
int len = v[x].size();
rep(i, 0, len) {
if(!flag[v[x][i]]) {
flag[v[x][i]] = true;
if(pre[v[x][i]] == -1 || find(pre[v[x][i]])) {
pre[v[x][i]] = x;
return true;
}
}
}
return false;
}

int hungary(int n) {
int ans = 0;
memset(pre, 255, sizeof(pre));
rep(i, 0, n) {
memset(flag, 0, sizeof(flag));
if(find(i)) ans++;
}
return ans;//ans即为所求的最大匹配
}


然后以hdu的1054作为例题

题目传送门http://acm.hdu.edu.cn/showproblem.php?pid=1054

(另一道poj上的二分匹配,不过加了二分枚举答案一步,链接点这儿

完全就是简单的匹配,不过建的是无向图而已

由于模板是在这道题做出之后才有的。。。所以模板的形式和题目AC的代码略有不同。。。

#include <iostream>
#include <cstdio>
#include <vector>
using namespace std;

#define MAX_N 1505

int pre[MAX_N];
bool flag[MAX_N];
vector<int> map[MAX_N];
int n;
int find(int cur)
{
int k;
vector<int>::iterator iter, end = map[cur].end();
for (iter = map[cur].begin(); iter < end; iter++)
{
k = *iter;
if (!flag[k])
{
flag[k] = true;
if (pre[k] == -1 || find(pre[k]))
{
pre[k] = cur;
return 1;
}
}
}
return 0;
}

int main()
{
int i, j, r, k, num, sum;
while (scanf("%d", &n) != EOF)
{
memset(pre, -1, sizeof(pre));
for (i = 0; i < n; i++) map[i].clear();
for (i = 0; i < n; i++)
{
scanf("%d:(%d)", &k, &num);
for (j = 0; j < num; j++)
{
scanf("%d", &r);
map[k].push_back(r);
map[r].push_back(k);
}
}
sum = 0;
for (i = 0; i < n; i++)
{
memset(flag, false, sizeof(flag));
sum += find(i);
}
printf("%d\n", sum / 2);
}

return 0;
}


当然这个问题里面还涉及到了最小点覆盖和最大匹配的关系,明显图中所有的点都可以在最大匹配的边集中找到包含这个点的边,所以只要从每个边上

各选一个点的话,这时这些点肯定满足覆盖。而如果减少一个点的话,这些点就相当于从一个不完全匹配的边集中找到的点,这时肯定有边集没有涉及

到的点,所以可以保证这时的答案是最小的符合条件的。而至于答案中是sum/2,是因为无向图的话,这个算法对同一条边会求两次,所以会除以2
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息