版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/monochrome00/article/details/81674507
题目链接<http://acm.hdu.edu.cn/showproblem.php?pid=3081>
题意:
n个女孩和n个男孩要一对一匹配。每个女孩可以选择自己喜欢的,也可以选择自己朋友喜欢的。朋友的关系是可以传递的。每一轮匹配,女孩匹配的男孩要不同,问最多能进行几轮的匹配。
题解一:
二分图匹配+删边+并查集。
每个女孩连接所有自己喜欢的和朋友喜欢的男孩。
每次进行一次二分图匹配,如果每个人都能被匹配就删去匹配的边。如果不能就输出答案。
#include<stdio.h>
#include<iostream>
#include<algorithm>
using namespace std;
#include<string.h>
int match[1005],vis[1005];
int n,m;
int mp[1005][1005];
bool dfs(int u){
for(int v=1;v<=n;v++){
if(mp[u][v]&&!vis[v]){
vis[v]=true;
if(match[v]==-1||dfs(match[v])){
match[v]=u;
return true;
}
}
}
return false;
}
int cal(){
memset(match,-1,sizeof(match));
for(int i=1;i<=n;i++){
memset(vis,0,sizeof(vis));
if(!dfs(i)) return i-1;
}
return n;
}
int t,f;
int fa[105];
int fd(int x){return x==fa[x]?x:fa[x]=fd(fa[x]);}
int main()
{
scanf("%d",&t);
while(t--){
scanf("%d%d%d",&n,&m,&f);
memset(mp,0,sizeof(mp));
int u,v;
for(int i=1;i<=m;i++){
scanf("%d%d",&u,&v);
mp[u][v]=1;
}
for(int i=1;i<=n;i++) fa[i]=i;
for(int i=1;i<=f;i++){
scanf("%d%d",&u,&v);
int fu=fd(u),fv=fd(v);
fa[fu]=fv;
}
for(int i=1;i<=n;i++){
for(int j=i+1;j<=n;j++){
int fi=fd(i),fj=fd(j);
if(fi!=fj) continue;
for(int k=1;k<=n;k++)
mp[i][k]=mp[j][k]=(mp[i][k]||mp[j][k]);
}
}
int ans=0;
while(1){
if(cal()<n) break;
ans++;
for(int i=1;i<=n;i++)
mp[match[i]][i]=0;
}
printf("%d\n",ans);
}
return 0;
}
题解二
二分答案+最大流+并查集。
每个女孩连接所有自己喜欢的和朋友喜欢的男孩。
二分一个答案,如果最大流的流量是n*mid,那就满足。
这就跟这题很像了:https://blog.csdn.net/monochrome00/article/details/81459335
#include<cstdio>
#include<cstring>
#include<queue>
#include<cmath>
#include<iostream>
using namespace std;
const int N=10007;
const int inf=1<<26;
struct Edge{
int u,v,w,nxt;
Edge(int u=0,int v=0,int w=0,int nxt=0):u(u),v(v),w(w),nxt(nxt){}
}edge[30*N];
int n,m,edn,sp,tp;
int p[N],d[N],c[N];
void add(int u,int v,int w){
edge[edn]=Edge(u,v,w,p[u]);p[u]=edn++;
edge[edn]=Edge(v,u,0,p[v]);p[v]=edn++;
}
bool bfs(){
memset(d,-1,sizeof(d));d[sp]=0;
queue<int>q;q.push(sp);
while(!q.empty()){
int u=q.front();
q.pop();
for(int i=p[u];~i;i=edge[i].nxt){
int v=edge[i].v;
if(d[v]==-1&&edge[i].w){
d[v]=d[u]+1;
q.push(v);
if(v==tp) return true;
}
}
}
return ~d[tp];
}
int dfs(int u,int b){
if(u==tp) return b;
int r=0;
for(int i=c[u];~i;i=edge[i].nxt){
int v=edge[i].v;
if(edge[i].w&&d[v]==d[u]+1){
int x=min(edge[i].w,b-r);
c[u]=i;
x=dfs(v,x);
r+=x;
edge[i].w-=x;
edge[i^1].w+=x;
if(r==b) break;
}
}
if(!r)d[u]=-2;
return r;
}
int dinic(){
int total=0,t;
while(bfs()){
memcpy(c,p,sizeof(p));
while(t=dfs(sp,inf))
total+=t;
}
return total;
}
int t,f;
int mp[105][105],fa[105];
int fd(int x){return x==fa[x]?x:fa[x]=fd(fa[x]);}
void build(int k){
memset(p,-1,sizeof(p));edn=0;
for(int i=1;i<=n;i++){
add(i+n,tp,k);
add(sp,i,k);
for(int j=1;j<=n;j++){
if(mp[i][j])
add(i,j+n,1);
}
}
}
int main()
{
scanf("%d",&t);
while(t--){
scanf("%d%d%d",&n,&m,&f);
memset(mp,0,sizeof(mp));
sp=0,tp=2*n+1;
int u,v;
for(int i=1;i<=m;i++){
scanf("%d%d",&u,&v);
mp[u][v]=1;
}
for(int i=1;i<=n;i++) fa[i]=i;
for(int i=1;i<=f;i++){
scanf("%d%d",&u,&v);
int fu=fd(u),fv=fd(v);
fa[fu]=fv;
}
for(int i=1;i<=n;i++){
for(int j=i+1;j<=n;j++){
int fi=fd(i),fj=fd(j);
if(fi!=fj) continue;
for(int k=1;k<=n;k++)
mp[i][k]=mp[j][k]=(mp[i][k]||mp[j][k]);
}
}
int lo=0,hi=100;
while(lo<=hi){
int mid=lo+hi>>1;
build(mid);
if(dinic()>=mid*n) lo=mid+1;
else hi=mid-1;
}
printf("%d\n",hi);
}
return 0;
}