/*
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;
}
HDU 3081 Marriage Match II(匈牙利算法 + 并查集)
最新推荐文章于 2018-10-07 11:56:38 发布