带花树(一般图最大匹配)(lzz)
“缩花”的思想虽然易懂,但与具体实现严重不符,其实根本没有“缩”的过程。建议用“增广路树+树上并查集维护信息”理解更直观
#include<cstdio>
#include<queue>
#include<cstring>
using namespace std;
const int N=1010;
int graph[N][N];
int n,m;
int match[N];
int fa[N];
int type[N];
int pre[N];
queue <int> q;
void swap(int &a,int &b)
{
int k=a; a=b; b=k;
}
int find(int x)
{
int k=x,i;
while(fa[k]!=k)k=fa[k];
while(fa[x]!=k)
{
i=fa[x]; fa[x]=k; x=i;
}
return k;
}
int vis[N],cnt=0;
int lca(int a,int b)
{
int k,i,j;
cnt++;
a=find(a); b=find(b);
while(vis[a]!=cnt)
{
vis[a]=cnt;
a=find(pre[match[a]]);
if(b)swap(a,b);
}
return a;
}
void shrink(int x,int root)
{
int k,i,j;
x=find(x);
while(x!=root)
{
k=pre[match[x]];
type[match[x]]=1;
q.push(match[x]);
if(find(k)!=root)pre[k]=match[x];
fa[x]=root; fa[find(match[x])]=root;
x=find(k);
}
return;
}
void bfs(int x)
{
int k,i,j;
int a,b,c;
for(k=1;k<=n;k++)type[k]=vis[k]=pre[k]=0;
for(k=1;k<=n;k++)fa[k]=k;
type[x]=1; pre[x]=0;
while(!q.empty())q.pop();
q.push(x);
while(!q.empty())
{
a=q.front(); q.pop();
for(k=1;k<=n;k++)
{
if(!graph[a][k])continue;
if(!type[k])
{
if(!match[k])
{
pre[k]=a;
while(k)
{
i=match[pre[k]];
match[k]=pre[k]; match[pre[k]]=k;
k=i;
}
return;
}
type[k]=2;
type[match[k]]=1;
pre[k]=a;
q.push(match[k]);
}
else if(type[k]==1 && find(a)!=find(k))
{
b=k;
c=lca(a,b);
if(find(a)!=c)pre[a]=b;
if(find(b)!=c)pre[b]=a;
shrink(a,c);
shrink(b,c);
}
}
}
return;
}
void blossom()
{
int k,i,j;
memset(match,0,sizeof(match));
for(k=1;k<=n;k++)
{
if(!match[k])bfs(k);
}
return;
}
int main()
{
int k,i,j;
int a,b,c;
int sum=0;
memset(graph,0,sizeof(graph));
scanf("%d%d",&n,&m);
for(k=0;k<m;k++)
{
scanf("%d%d",&a,&b);
graph[a][b]=graph[b][a]=1;
}
blossom();
for(k=1;k<=n;k++)if(match[k])sum++;
printf("%d\n",sum/2);
for(k=1;k<=n;k++)printf("%d ",match[k]);
printf("\n");
return 0;
}

浙公网安备 33010602011771号