码迷,mamicode.com
首页 > 其他好文 > 详细

一般图的最大匹配(模板)

时间:2019-10-21 22:16:31      阅读:106      评论:0      收藏:0      [点我收藏+]

标签:printf   mes   find   event   else   memset   路径   space   scan   

题:http://uoj.ac/problem/79

没什么好说的,只是区别于二分图

算法:带花树算法

技术图片
#include<bits/stdc++.h>
using namespace std;
#define fo(i,a,b) for(int i=a;i<=b;i++)
#define fod(i,a,b) for(int i=b;i>=a;i--)
const int N=550;
int n,head[N],pre[N],match[N],f[N],col[N],cmp[N],tot;
const int M=5e5+5;
struct node{
    int u,v,nextt;
}e[M];
int num;
void addedge(int u,int v){
    e[num].v=v;
    e[num].nextt=head[u];
    head[u]=num++;
}
int find(int x){
    return f[x]==x?x:f[x]=find(f[x]);
}
int lca(int x,int y){//整个lca实现比较巧妙,由于是BFS,那么这两个点在当前奇环上的深度一定相等,交替暴力寻找lca即可。 
    tot++;
    x=find(x),y=find(y);
    while(cmp[x]!=tot){
        cmp[x]=tot;
        x=find(pre[match[x]]);
        if(y)
            swap(x,y);
    }
    return x;
}
queue<int>que;
void make(int x,int y,int w){//缩环(开花)过程
    while(find(x)!=w){
        pre[x]=y,y=match[x];//x是原本的黑点,y是原本的白点,将原本的pre边变成双向。
        if(col[y]==2)//若y还是白点则染黑
            col[y]=1,que.push(y);
        if(find(x)==x)
            f[x]=w;
        if(find(y)==y)
            f[y]=w;
        x=pre[y];
    }
    
}
int  solve(int st){
    while(!que.empty())
        que.pop();
    que.push(st);
    fo(i,1,n)
        f[i]=i,pre[i]=col[i]=0;
    col[st]=1;//1 is black 
    while(!que.empty()){
        int u=que.front();
        que.pop();
        for(int i=head[u];~i;i=e[i].nextt){
            int v=e[i].v;
            if(find(v)==find(u)||col[v]==2)
                continue;//如果找到一个已经缩过的奇环或者偶环则跳过
            if(!col[v]){
                col[v]=2,pre[v]=u;
                if(!match[v]){//找到增广路
                    for(int x=v,y;x;x=y){//返回修改匹配
                        y=match[pre[x]];
                        match[x]=pre[x];
                        match[pre[x]]=x;
                    }
                    return 1;
                }
                //否则将其匹配点加入队列
                col[match[v]]=1;
                que.push(match[v]);
            }
            else{
                int LCA=lca(u,v);
                make(u,v,LCA);
                make(v,u,LCA);//以上分别修改到lca的路径以及v到lca的路径(环的两半)
            }
        }
    }
    return 0;
}
int main(){
    int m;
    memset(head,-1,sizeof(head));
    scanf("%d%d",&n,&m);
    fo(i,1,m){
        int u,v;
        scanf("%d%d",&u,&v);
        addedge(u,v);
        addedge(v,u);
    }
    int ans=0;
    fo(i,1,n)
        if(!match[i])
            ans+=solve(i);
    printf("%d\n",ans);
    fo(i,1,n)
        printf("%d ",match[i]);
    return 0;
}
View Code

 

一般图的最大匹配(模板)

标签:printf   mes   find   event   else   memset   路径   space   scan   

原文地址:https://www.cnblogs.com/starve/p/11716598.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!