Marriage Match III
Time Limit: 10000/4000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 2019 Accepted Submission(s): 593
Problem Description
Presumably, you all have known the question of stable marriage match. A girl will choose a boy; it is similar as the ever game of play-house . What a happy time as so many friends play 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. As 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. On the other hand, in order to play more times of marriage match, every girl can accept any K boys. If a girl chooses a boy, the boy must accept her unconditionally whether they had quarreled before or not.
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 an integer T, means the number of test cases.
Each test case starts with three integer n, m, K and f in a line (3<=n<=250, 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 1 2
1 1
2 3
3 2
4 2
4 4
1 4
2 3
Sample Output
3
Author
starvae
Source
HDOJ Monthly Contest – 2010.01.02
题目大意:有n*2个小孩,其中有n个女孩,有n个男孩,这些小孩玩过家家游戏,女孩选择和自己没吵过架的,或者选择和自己吵过架的但是这种情况有人数上限为k,然后对应如果当前女孩的朋友有一些没吵过架的男生,那么这个女孩也可以当做这些男孩和自己没吵过架,每一轮每个女孩都必须找一个男孩过家家,下一轮就不能选择之前自己选过的男孩进行过家家游戏,问最多能玩多少轮。
1、首先对于这一共能玩多少轮的问题,虽然一共只有250轮作为最大情况,然而我们每一次枚举一个数字作为可能解去进行判断的话,次数会比较多,O(n*n*n*M)是会超时的,所以我们要将这一维度时间复杂度降下去,因为其如果玩5轮的时候可以,那么玩4、3、2、1轮游戏都可以,如果玩7轮不可以,那么8、9.........都不可以,其满足递减性,那么我们可以进行二分查找。每一次枚举出一个当前情况进行判断,时间复杂度:O(logn*n^2m)
2、对于二分出的当前值mid,我们要跑最大流并判断是否可行,那么建图:
①建立源点S,连入各个女生,其权值设定为mid,表示一共玩mid轮游戏。
②建立汇点T,将各个男生连入汇点,其权值设定为mid,表示一共玩mid轮游戏。
③将每个女生节点拆点,一分为三,女生节点设定为u,女生选择没有吵过架的男生的节点设定为uu,女生选择吵过架的男生的节点设定为uuu。
④那么将女生节点u连入uu,其权值为mid,将女生节点u连入uuu,其权值为k,表示限制这个女生只能选k个吵过架的男生。
⑤那么对应,如果女生u和男生j没有吵过架,就用uu连入j,权值为1,表示这个女生只能选一次这个男生,同理,如果吵过架,就用uuu连入j,权值为1.
3、那么在建图之前,必须要处理的一个问题就是每个女生到底能有多少种选择的男生没有吵过架(因为女生的朋友如果和这个男生没有吵过架,那么就相当于这个女生和这个男生也没有吵过架)。那么我们建立并查集,如果两个女生是朋友,就加入到一个集合中,对于一个集合中的女生,其互相之间的选择都是想同的,O(n^3)处理一下就好。
4、那么整体思路就构建完毕了,剩下的内容就是写代码了.
Ac代码:
#include<stdio.h>
#include<string.h>
#include<iostream>
#include<queue>
using namespace std;
#define INF 0x3f3f3f3f
struct node
{
int from;
int to;
int w;
int next;
}e[1212121];
int divv[25500];
int head[25500];
int cur[25500];
int f[25500];
int map[355][355];
int n,m,kk,ff,ss,tt,cont;
void add(int from,int to,int w)
{
e[cont].to=to;
e[cont].w=w;
e[cont].next=head[from];
head[from]=cont++;
}
int find(int a)
{
int r=a;
while(f[r]!=r)
r=f[r];
int i=a;
int j;
while(i!=r)
{
j=f[i];
f[i]=r;
i=j;
}
return r;
}
void merge(int a,int b)
{
int A,B;
A=find(a);
B=find(b);
if(A!=B)
f[B]=A;
}
void getmap(int mid)
{
cont=0;
memset(head,-1,sizeof(head));
ss=4*n+1;
tt=ss+1;
for(int i=1;i<=n*3;i+=3)
{
add(ss,i,mid);
add(i,ss,0);
}
for(int i=1;i<=n*3;i+=3)
{
for(int j=1;j<=n;j++)
{
if(map[i/3+1][j]==1)
{
add(i+1,j+3*n,1);
add(j+3*n,i+1,0);
}
else
{
add(i+2,j+3*n,1);
add(j+3*n,i+2,0);
}
}
add(i,i+1,mid);
add(i+1,i,0);
add(i,i+2,kk);
add(i+2,i,0);
}
for(int i=1;i<=n;i++)
{
add(i+3*n,tt,mid);
add(tt,i+3*n,0);
}
}
int makedivv()
{
memset(divv,0,sizeof(divv));
divv[ss]=1;
queue<int >s;
s.push(ss);
while(!s.empty())
{
int u=s.front();
if(u==tt)return 1;
s.pop();
for(int i=head[u];i!=-1;i=e[i].next)
{
int v=e[i].to;
int w=e[i].w;
if(w&&divv[v]==0)
{
divv[v]=divv[u]+1;
s.push(v);
}
}
}
return 0;
}
int Dfs(int u,int maxflow,int tt)
{
if(u==tt)return maxflow;
int ret=0;
for(int &i=cur[u];i!=-1;i=e[i].next)
{
int v=e[i].to;
int w=e[i].w;
if(w&&divv[v]==divv[u]+1)
{
int f=Dfs(v,min(maxflow-ret,w),tt);
e[i].w-=f;
e[i^1].w+=f;
ret+=f;
if(ret==maxflow)return ret;
}
}
return ret;
}
int Slove(int mid)
{
getmap(mid);
int ans=0;
while(makedivv()==1)
{
memcpy(cur,head,sizeof(head));
ans+=Dfs(ss,INF,tt);
}
if(ans>=mid*n)return 1;
else return 0;
}
int main()
{
int t;
scanf("%d",&t);
while(t--)
{
memset(map,0,sizeof(map));
scanf("%d%d%d%d",&n,&m,&kk,&ff);
for(int i=0;i<=n;i++)f[i]=i;
for(int i=0;i<m;i++)
{
int x,y;
scanf("%d%d",&x,&y);
map[x][y]=1;
}
for(int i=0;i<ff;i++)
{
int x,y;
scanf("%d%d",&x,&y);
merge(x,y);
}
for(int i=1;i<=n;i++)
{
for(int j=1;j<=n;j++)
{
if(find(i)==find(j))
{
for(int k=1;k<=n;k++)
{
if(map[i][k]==1)
{
map[j][k]=1;
}
}
}
}
}
int ans=0;
int mid;
int l=0;
int r=25000;
while(r>=l)
{
mid=(l+r)/2;
if(Slove(mid)==1)
{
ans=mid;
l=mid+1;
}
else
{
r=mid-1;
}
}
printf("%d\n",ans);
}
}