HDU 3081 Marriage Match II —并查集,最大流

原题链接:http://acm.hdu.edu.cn/showproblem.php?pid=3081


Marriage Match II

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 1922    Accepted Submission(s): 679


Problem Description
Presumably, you all have known the question of stable marriage match. A girl will choose a boy; it is similar as the game of playing house we used to play when we are kids. What a happy time as so many friends playing together. And it is normal that a fight or a quarrel breaks out, but we will still play together after that, because we are kids. 
Now, there are 2n kids, n boys numbered from 1 to n, and n girls numbered from 1 to n. you know, ladies first. So, every girl can choose a boy first, with whom she has not quarreled, to make up a family. Besides, the girl X can also choose boy Z to be her boyfriend when her friend, girl Y has not quarreled with him. Furthermore, the friendship is mutual, which means a and c are friends provided that a and b are friends and b and c are friend. 
Once every girl finds their boyfriends they will start a new round of this game—marriage match. At the end of each round, every girl will start to find a new boyfriend, who she has not chosen before. So the game goes on and on.
Now, here is the question for you, how many rounds can these 2n kids totally play this game?
 

Input
There are several test cases. First is a integer T, means the number of test cases. 
Each test case starts with three integer n, m and f in a line (3<=n<=100,0<m<n*n,0<=f<n). n means there are 2*n children, n girls(number from 1 to n) and n boys(number from 1 to n).
Then m lines follow. Each line contains two numbers a and b, means girl a and boy b had never quarreled with each other. 
Then f lines follow. Each line contains two numbers c and d, means girl c and girl d are good friends.
 

Output
For each case, output a number in one line. The maximal number of Marriage Match the children can play.
 

Sample Input
  
  
1 4 5 2 1 1 2 3 3 2 4 2 4 4 1 4 2 3
 

Sample Output
  
  
2
 

Author
starvae

题意:有N个妹纸和N个汉纸。给出M组关系,表示妹纸A和汉纸B绝对不会吵架。再给出F组关系,表示妹纸C和妹纸D是好伙伴。如果C D是好伙伴的话,那么不会和C吵架的汉纸也不会和D吵架,同理不会和D吵架的汉纸也不会和C吵架。这个关系可以传递。即ABCD时好伙伴,那么她们其中一个人不与汉纸M吵架,其他人则也不会和M吵架。不吵架的男女就可配对。已知每一轮游戏,都需要每个妹纸分别和一个汉纸配对,而每个妹纸在每轮中的配对对象不能重复,问最多能进行多少轮游戏。游戏不能进行当且仅当有妹纸找不到在之前游戏中没有配对过的汉纸。

解题思路:考察网络流和构图,也用到了并查集。首先妹纸们的传递关系可以用并查集解决。就可以求得每个妹纸可以和哪些汉纸配对。最多可以多少轮用二分。然后就就是构图了。源点向每个妹纸连容量为mid的边,这样就可以确保每个妹子都要参加mid轮,每个汉纸向汇点连容量为mid的边,同样道理。然后每个妹纸向不会和她吵架的每一个汉纸连容量是1的边。跑最大流看是否满流。接下来就是模板了。


AC代码:

#include"iostream"
#include "stdio.h"
#include "queue"
using namespace std;
#define N 10000
#define M 10000000
#define INF 1000000000

int head[N], cur[N], d[N], st[M], s, e, no, n,nxxx;         //求最大流,dinic算法模板

struct point{                          
	int u, v, flow, next;
	point(){};
	point(int x, int y, int z, int w):u(x), v(y), next(z), flow(w){};
}p[M];


void add(int x, int y, int z){
	p[no] = point(x, y, head[x], z);	head[x] = no++;
	p[no] = point(y, x, head[y], 0);	head[y] = no++;
}
void init(){
	memset(head, -1, sizeof(head));
	no = 0;
}

bool bfs(){
	int i, x, y;
	queue
   
   
    
    q;
	memset(d, -1, sizeof(d));
	d[s] = 0;	q.push(s);
	while(!q.empty()){
		x = q.front();	q.pop();
		for(i = head[x]; i != -1; i = p[i].next){
			if(p[i].flow && d[y = p[i].v] < 0){
				d[y] = d[x] + 1;
				if(y == e)	return true;
				q.push(y);
			}
		}
	}
	return false;
}

int dinic(){
	int i, loc, top, x = s, nowflow, maxflow = 0;
	while(bfs()){
		for(i = s; i <= e; i++)	cur[i] = head[i];
		top = 0;
		while(true){
			if(x == e){
				nowflow = INF;
				for(i = 0; i < top; i ++){
					if(nowflow > p[st[i]].flow){
						nowflow = p[st[i]].flow;
						loc = i;
					}
				}
				for(i = 0; i < top; i++){
					p[st[i]].flow -= nowflow;
					p[st[i]^1].flow += nowflow;
				}
				maxflow += nowflow;
				top = loc;	x = p[st[top]].u;
			}
			for(i = cur[x]; i != -1; i = p[i].next)
				if(p[i].flow && d[p[i].v] == d[x] + 1) break;
			cur[x] = i;
			if(i != -1){
				st[top ++] = i;
				x = p[i].v;
			}
			else {
				if(!top)	break;
				d[x] = -1;
				x = p[st[--top]].u;
			}
		}
	}
	return maxflow;
}

struct xxx                  //记录有多少可配对选择
{
	int g,b;
} coup[10000];

int par[110],rank1[110];

void init2()                           //并查集模板
{
	for(int i=0;i<110;i++)
	{
		par[i]=i;
		rank1[i]=0;
	}
}

int find(int x)
{
	if(par[x]==x)
		return x;
	else
		return par[x]=find(par[x]);
}

void unite(int x,int y)
{
	x=find(x);
	y=find(y);
	if(x==y)
		return;
	if(rank1[x]
    
    
   
   


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值