poj3041 最小点覆盖==二分图最大匹配 匈牙利算法求解最大匹配问题(运用DFS)



//poj3041 二分图 可以做一款手势消灭星星的小游戏
//第一次见到二分图的匈牙利算法,需要好好学习一下,否则就只会复杂度为边数的指数级的方法,还WA。。。
//最小点覆盖:假如选了一个点就相当于覆盖了以它为端点的所有边,你需要选择最少的点来覆盖图的所有的边。
//最小点覆盖数 = 最大匹配数
//用增广路求最大匹配的方法----匈牙利算法
//若P是图G中一条连通两个未匹配顶点的路径,并且属于M的边和不属于M的边(即已匹配和待匹配的边)在P上交替出现,则称P为相对于M的一条增广路径。
//由增广路的定义可以推出下述三个结论:
//1、P的路径个数必定为奇数,第一条边和最后一条边都不属于M。
//2、将M和P进行取反操作可以得到一个更大的匹配M’
//(反操作:把P中的 匹配边 与 非匹配边 互换)
//3、M为G的最大匹配当且仅当不存在M的增广路径P
//匈牙利算法轮廓:
//(1)置M为空
//(2)找出一条增广路径P(dfs),通过异或操作获得更大的匹配M’代替M
//(3)重复(2)操作直到找不出增广路径为止

//poj3041 最小点覆盖==二分图最大匹配 匈牙利算法
//可以做一款手势消灭星星的小游戏
#include <iostream>
using namespace std;
int m;
int grid[505][505];
bool visit[505];
int link[505];
bool dfs(int x, int n)
{
	for (int i = 1; i <= n; i++)
	{
		if (grid[x][i] == 1 && visit[i] == false)
		{
			visit[i] = true;
			if (link[i] == 0 || dfs(link[i], n))	//若I未匹配,则配给x。若I已经匹配,则询问是否可以让I的匹配者换一个,如果可以的话,I归属x,不可以的话,x继续查找。
			{
				link[i] = x;
				return true;
			}
		}
	}
	return false;
}
int search(int n)
{
	for (int i = 1; i <= n; i++)
	{
		memset(visit, 0, sizeof(visit));
		if (dfs(i, n))
			m++;
	}
	return m;
}
int main()
{
	int a, b;
	cin >> a >> b;
	m = 0;
	memset(grid, 0, sizeof(grid));
	for (int i = 0; i < b; i++)
	{
		int r, c;
		cin >> r >> c;
		grid[r][c] = 1;
	}
	cout << search(a) << endl;

	return 0;
}


 

猜你喜欢

转载自blog.csdn.net/chchlh/article/details/41912311