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

13 篇文章 0 订阅
7 篇文章 0 订阅

嗯。。。。今天开始写博客。。。。大一过去一半了。。。希望下半年能有个好的开始吧

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

算法轮廓:
⑴置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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值