HDU 3081 Marriage Match II(匈牙利算法 + 并查集)

/*
WA,但是不知道原因
题意:2*n个同学,n个男生,n个女生,m组数据表示两同学之间没有争吵,女同学中f组朋友。女同学寻找男朋友,如果他们之间或者她的朋友与那个男生之间无争吵,则可以作男朋友。当所有女生都找到男朋友后,则完成一轮。问最终有多少轮。
题解:匈牙利算法 + 并查集
问题显然是二分图最大匹配问题,如果最大匹配为n,则完成一轮。每完成一轮,需要进行一些处理,相同女同学不能选择同样的男生作为男朋友。因为女同学朋友之间是相互的,用并查集可以得到很好地解决。
*/

#include <iostream>
#define re(i, n) for(int i = 0; i < n; ++ i)
using namespace std;

const int nMax = 105;
int p[nMax];
int link[nMax];
int useif[nMax];
int map[nMax][nMax];
//int fhash[nMax][nMax];
int T, n, m, f;

int find(int x)//并查集
{
	return p[x] == x ? x : p[x] = find(p[x]);
}

int getPath(int t)//寻找增广路经
{
	re(i, n)
	{
		if(!useif[i] && map[t][i])
		{
			useif[i] = 1;
			if(link[i] == -1 || getPath(link[i]))
			{
				link[i] = t;
				return 1;
			}
		}
	}
	return 0;
}

int getNum()//匈牙利算法,匈牙利算法最坏复杂度O(N^3)
{
	int sum = 0;
	memset(link, -1, sizeof(link));
	re(i, n)
	{
		memset(useif, 0, sizeof(useif));
		sum += getPath(i);
	}
	if(sum == n)
		re(i, n)
		{
			map[link[i]][i] = 0;
		}
	return sum;
}

int main()
{
	//freopen("f://data.in", "r", stdin);
	scanf("%d", &T);
	while(T --)
	{
		scanf("%d %d %d", &n, &m, &f);
		int a, b;
		re(i, m)
		{
			scanf("%d %d", &a, &b);
			-- a;
			-- b;
			map[a][b] = 1;
		}
		re(i, n)
			p[i] = i;
		re(i, f)
		{
			scanf("%d %d", &a, &b);
			-- a;
			-- b;
			if(find(a) != find(b))
				p[a] = find(b);
		}
		/*
		re(i, n) re(j, n)//这里曾经出错,第二个误写成re(j, m),纠结了好久
		{
			if(map[i][j])
			{
				map[find(i)][find(j)] = 1;
			}
		}*/
		re(i, n)//朋友间关系的处理,如果i和j互为朋友,且j和k无争吵,则i和k也无争吵
		{
			int si = find(i);
			re(j, n)
				if(i != j && si == find(j))
					re(k, n)
					if(map[j][k])
						map[i][k] = 1;
		}
		//memset(fhash, 0, sizeof(fhash));
		int ans = 0;
		while(getNum() == n) ans ++;
		printf("%d\n",ans);
	}
	return 0;
}

你可能感兴趣的:(算法)