HDU 2444 The Accomodation of Students二分图判定和匈牙利算法

本题就是先判断是否可以组成二分图,然后用匈牙利算法求出最大匹配。


到底如何学习一种新算法呢?

我也不知道什么方法是最佳的了,因为看书本和大牛们写的匈牙利算法详细分析,看了差不多两个小时没看懂,最后自己直接看代码,居然不到半个小时看懂了。然后就可以直接拿来解题啦。

比如topcoder上有这个算法的很详细的分析,真没看懂。

代码居然比分析更清晰了?我也不好下结论。


但是我觉得主要的思想还是有作用的。

说说我对这个算法的理解吧:

1 假设二分图分为两个集合 U, V,那么从一个集合U出发

2 U的一个点u连线到V的一个点v,如果v点没有别的点连接,那么就算连接成功了

3 如果v点有别的点u2连接了,那么就u2就需要让u连接,然后u2递归寻找别的路径点去连接,如果寻找成功找到v2,那么u2就连接v2;

4 如果u2没有找到别的点连接,那么u2就不让u了,所以u就不能连接v了。

5 那么u就继续寻找别的点连接,重复上述过程,直到u没找到别的点连接,那么u就是连接失败。继续下一个点查找。

就是一个递归查找的过程。


这位大牛的分析,我也是没看懂:https://www.byvoid.com/blog/hungary

但是可以参考他的图,然后按照我上面说的方法连接下面的图,保证你懂了:



本题C++程序:

bool isBipartite_2(vector<vector<bool> > & stus, int src)
{
	vector<int> colors(stus.size(), -1);
	colors[src] = 0;
	queue<int> qu;
	qu.push(src);
	while (qu.size())
	{
		int u = qu.front();
		qu.pop();
		for (int v = 0; v < (int)stus.size(); v++)
		{
			if (stus[u][v] && colors[v] == -1)
			{
				colors[v] = 1 - colors[u];
				qu.push(v);
			}
			else if (stus[u][v] && colors[v] == colors[u]) return false;
		}
	}
	return true;
}

bool hunDfs_2(vector<vector<bool> > &stus,  vector<bool> &used, 
		    vector<int> &linker, int src)
{
	for (int d = 0; d < (int)stus.size(); d++)
	{
		if (stus[src][d] && !used[d])
		{
			used[d] = true;
			if (linker[d] == -1 ||
				hunDfs_2(stus, used, linker, linker[d]))
			{
				linker[d] = src;
				return true;
			}
		}
	}
	return false;
}

int hungary_2(vector<vector<bool> > &stus)
{
	int res = 0;
	vector<int> linker(stus.size(), -1);
	for (int i = 0; i < (int)stus.size(); i++)
	{
		vector<bool> used(stus.size(), false);
		if (hunDfs_2(stus, used, linker, i)) res++;
	}
	return res;
}

int main()
{
	int n, m, u, v;
	while (scanf("%d %d", &n, &m) != EOF)
	{
		vector<vector<bool> > stus(n, vector<bool>(n, 0));
		while (m--)
		{
			scanf("%d %d", &u, &v);
			stus[u-1][v-1] = stus[v-1][u-1] = true;//记得:这是个无向图,否则错
		}
		if (isBipartite_2(stus, 0))
		{
			printf("%d\n", hungary_2(stus)>>1);
		}
		else puts("No");
	}
	return 0;
}


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值