Marriage Match II HDU - 3081
题意:
有n个男生和n个女生,在玩过家家。每一轮都配对一对夫妻。
限制:
- 下一轮的配对时,两个男女在之前不能配对过。
- 女生不会和quarrel过的人配对。
- 女生只能和没有和朋友quarrel过的男生配对。
思路:
对于女生的朋友,用并查集维护。
- 对于m里的每对,肯定没有quarrel的:g1和b1.
把g1和g1的朋友都与b1连边。(边权为1) - 之后二分答案。mid为轮数。
- 把
源点
和每个女生
相连,边权为mid。 - 把
每个男生
和汇点
相连,边权也为mid。 - 跑最大流检验答案。
AC
#include <iostream>
#include <vector>
#include <cstring>
#include <queue>
#include <cstdio>
#include <algorithm>
#define sz(a) ((int)a.size())
#define pb push_back
#define For(i,x,y) for(int i=(x); i<=(y); i++)
#define eb emplace_back
#define mst(x,a) memset(x,a,sizeof(x))
#define fzhead EDGE(int u, int v, int c, int f)
#define fzbody from(u), to(v), cap(c), flow(f)
using namespace std;
const int maxn=200+10;
const int inf =0x3f3f3f3f;
struct EDGE{
int from,to,cap,flow;
EDGE(){}
fzhead:fzbody{}
};
struct Dinic{
int n,m,s,t;
vector<EDGE> edges;
vector<int> g[maxn];
bool vis[maxn];
int d[maxn];
int cur[maxn];
///cur就是记录当前循环到了哪一条边。
void init(int n){
this->n = n;
for(int i=0; i<n; i++)g[i].clear();
edges.clear();
}
void add(int from, int to, int cap){
// edges.eb(from,to,cap,0);
//edges.eb(to,from,0,0);
edges.pb({from,to,cap,0});
edges.pb({to,from,0,0});
///加边同时,加正向和反向。
m=edges.size();
g[from].pb(m-2);
g[to].pb(m-1);
}
bool bfs(){
mst(vis,0);
mst(d,0);
queue<int>q;
q.push(s);
d[s]=0;
vis[s]=1;///源点深度为1.
while(!q.empty())
{
int x=q.front();q.pop();
for(int i=0; i<sz(g[x]); i++)
{
EDGE&e=edges[g[x][i]];
if(!vis[e.to]&&e.cap>e.flow){
vis[e.to]=1;
d[e.to]=d[x]+1;
q.push(e.to);
}
}
}
return vis[t];///当汇点的深度不存在时,说明不存在分层图。
}
int dfs(int x, int a){
///x为当前节点,a为流量。
if(x==t || a==0)return a;///当已经到达汇点,或者流量不存在时,返回。
int flow=0,f;
for(int &i=cur[x]; i<sz(g[x]); i++){
///注意这里的“&”符号,这样i增加同时也能改变cur【x】的值,达到弧优化的目的。
EDGE& e=edges[g[x][i]];
if(d[x]+1==d[e.to]&&(f=dfs(e.to,min(a,e.cap-e.flow)))>0){///判断并且增广。
e.flow+=f;///加减
edges[g[x][i]^1].flow-=f;
flow+=f;
a-=f;
if(a==0)break;
}
}
return flow;
}
int maxflow(int s, int t){
this->s=s,this->t=t;
int flow=0;
while(bfs()){
///每一次建立分层图后,都要把cur置为每一个点的第一条边
mst(cur,0);
flow+=dfs(s,inf);
}
return flow;
}
} dinic;
struct point {
int a,b;
}p[10000+10];
int n,m,f,fa[200],vis[200][200];
void init(){
for(int i=1; i<=n; i++)fa[i]=i;
}
int find(int x){
if(x==fa[x])return x;
return fa[x]=find(fa[x]);
}
void unio(int u, int v){
int A=find(u),B=find(v);
if(A!=B)fa[A]=B;
return ;
}
int st,ed;
void build(int w){
dinic.init(maxn);
st=0;ed=n+n+1;
for(int i=1; i<=n; i++)dinic.add(st,i,w);
for(int i=1; i<=n; i++)dinic.add(i+n,ed,w);
mst(vis,0);
for(int i=1; i<=m; i++){
int u=p[i].a,v=p[i].b;
for(int j=1; j<=n; j++){
if(find(u)==find(j)&&!vis[j][v]){
vis[j][v]=1;
dinic.add(j,v+n,1);
}
}
}
}
int check(int mid){return dinic.maxflow(st,ed)==n*mid;}
int main()
{
int t;scanf("%d", &t);
while(t--){
scanf("%d%d%d", &n, &m, &f);
int u,v;
init();
For(i,1,m)scanf("%d%d", &u, &v),p[i]={u,v};
For(i,1,f)scanf("%d%d", &u, &v),unio(u,v);
int l=0, r=n,ans=0;
while(l<=r){
int mid=(l+r)>>1;
build(mid);
// int tmp=check();cout<<tmp<<' '<<mid<<endl;
if(check(mid)){
ans=mid;
l=mid+1;
}
else r=mid-1;
}
printf("%d\n",ans);
}
return 0;
}