• 一般图最大匹配(带花树)


    带花树

    Hungary算法的核心就是找增广路。
    但是在一般图上,因为有奇环,所以找增广路的时候可能会绕一个奇环一圈然后多次经过同一条边,所以不可以直接Hungary。
    注意到对于一个奇环,一定有至少一个点能跟环外匹配,所以我们可以考虑把奇环缩成一个点(开花)。
    考虑bfs,并对节点黑白染色。假设起点是黑点,那么队列中只保存黑点。
    很显然黑->白的边是非匹配边,白->黑的边是匹配边。
    我们遍历当前队首黑点(u)的出点(v),如果(v)未被染色,就将其染成白色。
    如果(v)已经匹配了,那么将其匹配点染成黑色并加入队列。
    否则我们就找到了一条增广路。
    (v)是白点,那么我们找到了一个偶环,这对匹配没有任何影响,可以直接忽略。
    (v)是黑点,那么我们找到了一个奇环,在bfs树上找到这两个点的lca,然后开花。
    因为奇环开花后是一个黑点,所以环上的白点需要被改成黑点并加入队列。
    我们一般用并查集来记录每个点在哪个花中。
    同时为了能够沿着增广路走回去,我们需要记录一个(pre)表示这个点的前驱。
    花上的非匹配边的(pre)是双向的,有点像双向链表,缩环时需要处理。

    #include<queue>
    #include<cstdio>
    #include<vector>
    #include<cstring>
    #include<numeric>
    #include<algorithm>
    const int N=507;
    int n,fa[N],col[N],mat[N],pre[N];std::vector<int>e[N];std::queue<int>q;
    int read(){int x;scanf("%d",&x);return x;}
    int find(int x){return x==fa[x]? x:fa[x]=find(fa[x]);}
    int lca(int u,int v)
    {
        static int f[N],t;++t;
        for(;f[u]^t;std::swap(u,v)) if(u) f[u]=t,u=find(pre[mat[u]]);
        return u;
    }
    void blossum(int u,int v,int p){for(;find(u)^p;u=pre[v]) if(pre[u]=v,v=mat[u],fa[u]=fa[v]=p,col[v]==1) col[v]=2,q.push(v);}
    int bfs(int s)
    {
        while(!q.empty()) q.pop();
        memset(col+1,0,n<<2),std::iota(fa+1,fa+n+1,1),q.push(s),col[s]=2;
        while(!q.empty())
        {
    	int u=q.front(),p;q.pop();
    	for(int v:e[u])
    	    if(!col[v])
    	    {
    		col[v]=1,pre[v]=u,col[mat[v]]=2,q.push(mat[v]);
    		if(!mat[v])
    		{
    		    while(u) u=mat[pre[v]],mat[v]=pre[v],mat[pre[v]]=v,v=u;
    		    return 1;
    		}
    	    }
    	    else if(col[v]==2) p=lca(u,v),blossum(u,v,p),blossum(v,u,p);
        }
        return 0;
    } 
    int main()
    {
        n=read();int m=read(),ans=0;
        for(int i=1,u,v;i<=m;++i) u=read(),v=read(),e[u].push_back(v),e[v].push_back(u);
        for(int i=1;i<=n;++i) if(!mat[i]&&bfs(i)) ++ans;
        printf("%d
    ",ans);
        for(int i=1;i<=n;++i) printf("%d ",mat[i]);
    }
    
  • 相关阅读:
    listView控件演示程序
    猪悟能淘宝商品下载专家v3版开发手记
    c# WebClient类
    分隔控件splitter演示程序
    C#中SESSIONID的获取
    工具栏toolBar演示程序
    Cookie总结
    C#获取网页源码并且自动判断网页字符集编码
    如何在Google Code上建立私有代码版本库
    iOS应用程序生命周期(前后台切换,应用的各种状态)详解
  • 原文地址:https://www.cnblogs.com/cjoierShiina-Mashiro/p/12717850.html
Copyright © 2020-2023  润新知