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


    题: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
    ",ans);
        fo(i,1,n)
            printf("%d ",match[i]);
        return 0;
    }
    View Code
  • 相关阅读:
    三数之和
    盛最多水的容器
    正则表达式匹配
    最长回文子串
    寻找两个有序数组的中位数
    2、二维数组中的查找
    1、找出数组中重复的数字
    mongodb的下载地址
    提取快捷方式的图标资源问题
    一条数据引发的问题
  • 原文地址:https://www.cnblogs.com/starve/p/11716598.html
Copyright © 2020-2023  润新知