标签:
1 4 5 2 1 1 2 3 3 2 4 2 4 4 1 4 2 3
2
题意:
有 2*n个同学,n男n女,有 m 对男女之间木有吵过架(有关系),f 对女生互为朋友(有关系),现在这 n 个女生要找对象,要求没有和她吵过架或者没有和她朋友吵过架,
当 n 个女生都找到对象的时候算作一轮,然后重新找,满足每个女生都不能找和上次一样的对象,问最多能进行多少轮。(可以理解为经过多少轮游戏不存在完美匹配)。
解析:
首先把女生之间的关系传递闭包一下。有关系的男女之间建边,构造二分图。每次用匈牙利算法求一下最大匹配。若是完美匹配,删去当前的边,接着求最大匹配,直到不是完美匹配为止。
#include <cstdio>
#include <cstring>
#include <algorithm>
#define maxn 110
using namespace std;
int map[maxn][maxn];//男女关系
int node[maxn][maxn];//女生之间的朋友关系
int used[maxn];
int link[maxn];
int n, m, f;
void init(){
memset(map, 0, sizeof(map));
memset(node, 0, sizeof(node));
}
void floyd(){
for(int k = 1; k <= n; ++k)
for(int i = 1; i <= n; ++i)
for(int j = 1; j <= n; ++j)
node[i][j] = node[i][j] || (node[i][k] && node[k][j]);
}
void getmap(){
scanf("%d%d%d", &n, &m, &f);
int a, b;
while(m--){
scanf("%d%d", &a, &b);
map[a][b] = 1;
}
while(f--){
scanf("%d%d", &a, &b);
node[a][b] = node[b][a] = 1;
}
floyd();
for(int i = 1; i <= n; ++i){//枚举每一个女生
for(int j = 1; j <= n; ++j){
if(node[i][j]){//女生i , j之间为朋友关系
for(int k = 1; k <= n; ++k){
//若女生i 和男生 k 可以做伴侣,
//则女生j 和男生 k 也可以做伴侣
if(map[i][k])
map[j][k] = 1;
}
}
}
}
}
bool dfs(int x){
for(int i = 1; i <= n; ++i){
if(map[x][i] && !used[i]){
used[i] = 1;
if(link[i] == -1 || dfs(link[i])){
link[i] = x;
return true;
}
}
}
return false;
}
int hungary(){
int ans = 0;
memset(link, -1, sizeof(link));
for(int i = 1; i <= n; ++i){
memset(used, 0, sizeof(used));
if(dfs(i))
ans++;
}
return ans;
}
void solve(){
int num = 0;
while(1){
int sum = hungary();
if(sum == n){
num++;
for(int i = 1; i <= n; ++i)
map[link[i]][i] = 0;
}
else
break;
}
printf("%d\n", num);
}
int main (){
int T;
scanf("%d", &T);
while(T--){
init();
getmap();
solve();
}
return 0;
}
版权声明:本文为博主原创文章,未经博主允许不得转载。
HDU 3081--【二分图 && 传递闭包 && 完美匹配次数 && 经典】
标签:
原文地址:http://blog.csdn.net/hpuhjh/article/details/48001199