1 4 5 2 1 1 2 3 3 2 4 2 4 4 1 4 2 3
2
这道题一开始我用匈牙利+删边做的,后来做网络流时看了一位大神的博客上的一段分析深有体会,又用最大流做了一遍。
链接:http://blog.csdn.net/qq564690377/article/details/7857983
这里我就只分析二分匹配了,其实很简单,就是根据并查集将该连的关系全都连起来,然后有匈牙利跑一遍,
每跑一遍就将当前节点(女孩)与其当前匹配的节点(男孩)关系删掉,再继续跑匈牙利,直到跑出的最大
匹配数小与n为止,此时跑的遍数就是最大轮数。
现上代码:
网络流:
#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<iostream>
#include<queue>
#define Min(a,b) a<b?a:b
#define inf 1000000000
#define maxn 20000
#define maxh 400
using namespace std;
typedef struct //前向星存图
{
int to,next,w;
}node;
typedef struct
{
int x,t;
}dep;
node E[maxn];
int head[maxh],headx[maxh],deep[maxh],cnt;
int set[maxh],map[maxh][maxh];
int n,m,f;
////////////////////////////////wangluoliu//////////////////////////////
void init()
{
memset(head,-1,sizeof(head));
cnt=0;
}
void add(int a,int b,int c)
{
E[cnt].to=b;
E[cnt].w=c;
E[cnt].next=head[a];
head[a]=cnt++;
E[cnt].to=a;
E[cnt].w=0;
E[cnt].next=head[b];
head[b]=cnt++;
}
int min(int x,int y)
{
return x<y?x:y;
}
int bfs(int s,int t,int n)
{
memset(deep,255,sizeof(deep));
queue<dep>Q;
dep fir,nex;
fir.x=s;
fir.t=0;
deep[s]=0;
Q.push(fir);
while(!Q.empty())
{
fir=Q.front();
Q.pop();
for(int i=head[fir.x];i+1;i=E[i].next)
{
nex.x=E[i].to;
nex.t=fir.t+1;
if(deep[nex.x]!=-1||!E[i].w)
continue;
deep[nex.x]=nex.t;
Q.push(nex);
}
}
for(int i=0;i<=n;i++)
headx[i]=head[i];
return deep[t]!=-1;
}
int dfs(int s,int t,int flow)
{
if(s==t)
return flow;
int newflow=0;
for(int i=headx[s];i+1;i=E[i].next)
{
headx[s]=i;
int to=E[i].to;
int w=E[i].w;
if(!w||deep[to]!=deep[s]+1)
continue;
int temp=dfs(to,t,min(w,flow-newflow));
newflow+=temp;
E[i].w-=temp;
E[i^1].w+=temp;
if(newflow==flow)
break;
}
if(!newflow)deep[s]=0;
return newflow;
}
int Dinic(int s,int t,int m)
{
int sum=0;
while(bfs(s,t,m))
{
sum+=dfs(s,t,inf);
}
return sum;
}
////////////////////////////////bingchaji///////////////////////////////////
int findx(int x)
{
if(set[x]!=x)
set[x]=findx(set[x]);
return set[x];
}
void fun(int x,int y)
{
x=findx(x);
y=findx(y);
if(x!=y)
set[x]=y;
}
//////////////////////////////////////jiantu////////////////////////////
void built(int mid)
{
init();//前向星初始化
int s=2*n+1,t=2*n+2;
for(int i=1;i<=n;i++)
{
add(s,i,mid);
add(i+n,t,mid);
for(int j=1;j<=n;j++)
{
if(map[i][j])
{
add(i,j+n,1);
}
}
}
}
////////////////////////////////////////////////////////////////////////
int main()
{
int T;
int a,b;
int l,r,mid;
scanf("%d",&T);
while(T--)
{
scanf("%d%d%d",&n,&m,&f);
for(int i=0;i<=n;i++)//初始化
{
set[i]=i;
for(int j=0;j<=n;j++)
map[i][j]=0;
}
for(int i=0;i<m;i++)
{
scanf("%d%d",&a,&b);
map[a][b]=1;
}
for(int i=0;i<f;i++)
{
scanf("%d%d",&a,&b);
fun(a,b);
}
for(int i=1;i<=n;i++)
{
int xi=findx(i);
for(int j=1;j<=n;j++)
{
int yi=findx(j);
if(xi==yi&&i!=j)
{
for(int k=1;k<=n;k++)
{
if(map[j][k])
{
map[i][k]=1;
}
}
}
}
}
l=0,r=n+1;
while(l!=r-1)
{
// printf("xcwdf\n");
mid=(l+r)/2;
built(mid);
if(Dinic(2*n+1,2*n+2,2*n+2)==n*mid)
{
l=mid;
}
else
{
r=mid;
}
}
printf("%d\n",l);
}
return 0;
}
二分匹配:
#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<iostream>
#define maxn 200
using namespace std;
int markd[maxn],markx[maxn],xm[maxn][maxn];
int set[maxn];
int n,m,f;
int findx(int x)
{
if(x!=set[x])
set[x]=findx(set[x]);
return set[x];
}
void fun(int x,int y)
{
x=findx(x);
y=findx(y);
if(x!=y)
{
set[y]=x;
}
}
int xyl(int x)
{
for(int i=1;i<=n;i++)
{
if(xm[x][i]&&!markd[i])
{
markd[i]=1;
if(markx[i]==-1||xyl(markx[i]))
{
markx[i]=x;
return 1;
}
}
}
return 0;
}
int main()
{
int T;
int a,b;
scanf("%d",&T);
while(T--)
{
scanf("%d%d%d",&n,&m,&f);
memset(xm,0,sizeof(xm));
for(int i=1;i<=n;i++)
set[i]=i;
for(int i=1;i<=m;i++)
{
scanf("%d%d",&a,&b);
xm[a][b]=1;
}
for(int i=1;i<=f;i++)
{
scanf("%d%d",&a,&b);
fun(a,b);
}
for(int i=1;i<=n;i++)
{
int xi=findx(i);
for(int j=1;j<=n;j++)
{
int yi=findx(j);
if(xi==yi&&i!=j)
{
for(int k=1;k<=n;k++)
{
if(xm[j][k])
xm[i][k]=1;
}
}
}
}
int cnt=0;
while(1)
{
memset(markx,255,sizeof(markx));
int sum=0;
for(int i=1;i<=n;i++)
{
memset(markd,0,sizeof(markd));
sum+=xyl(i);
}
if(sum<n)
break;
cnt++;
for(int i=1;i<=n;i++)
{
xm[markx[i]][i]=0; //删掉当前匹配边
}
}
printf("%d\n",cnt);
}
return 0;
}
hdu 3081 【二分匹配+并查集+删边||最大路+并查集+二分枚举】
原文:http://blog.csdn.net/letterwuyu/article/details/42870651