zoukankan      html  css  js  c++  java
  • UOJ79 一般图最大匹配

    题目描述

    从前一个和谐的班级,所有人都是搞OI的。有 nn 个是男生,有 00 个是女生。男生编号分别为 1,,n1,…,n。

    现在老师想把他们分成若干个两人小组写动态仙人掌,一个人负责搬砖另一个人负责吐槽。每个人至多属于一个小组。

    有若干个这样的条件:第 vv 个男生和第 uu 个男生愿意组成小组。

    请问这个班级里最多产生多少个小组?

    输入格式

    第一行两个正整数,n,mn,m。保证 n2n≥2。

    接下来 mm 行,每行两个整数 v,uv,u 表示第 vv 个男生和第 uu 个男生愿意组成小组。保证 1v,un1≤v,u≤n,保证 vuv≠u,保证同一个条件不会出现两次。

    输出格式

    第一行一个整数,表示最多产生多少个小组。

    接下来一行 nn 个整数,描述一组最优方案。第 vv 个整数表示 vv 号男生所在小组的另一个男生的编号。如果 vv 号男生没有小组请输出 00。

    样例一

    input

    10 20
    9 2
    7 6
    10 8
    3 9
    1 10
    7 1
    10 9
    8 6
    8 2
    8 1
    3 1
    7 5
    4 7
    5 9
    7 8
    10 4
    9 1
    4 8
    6 3
    2 5
    
    

    output

    5
    9 5 6 10 2 3 8 7 1 4 
    
    

    样例二

    input

    5 4
    1 5
    4 2
    2 1
    4 3
    
    

    output

    2
    2 1 4 3 0 
    

     

    正解:带花树算法

    解题报告:

      这道题是一般图最大匹配,也就是带花树算法裸题。

      大概讲一下一般图最大匹配的思想:一般图最大匹配由带花树算法实现,2015年国家集训队论文中我校学长陈胤伯详细介绍了这一算法。

      考虑一般图与二分图最大的不同就在于一般图存在奇环,所以我们不能完全套用二分图最大匹配的算法。

      在这里不加以证明的给出具体做法(证明详见2015年国家队论文):

      每次从一个未盖点出发,将其命名为偶点(偶点匹配的点称之为奇点),枚举其出边以及出边连接的点v:

      如果v在本次BFS中还未被经过,则假设未匹配,那么找到了一条增广路,原路返回,把原来的匹配边和非匹配边取反,这样可以使答案加一;否则,将v的匹配点加入队列中拓展,根据我们上面的定义,v的匹配点显然也是偶点。

      如果v已经访问过,那么显然出现了环,这个环如果是偶环则不用考虑,如果是奇环且本身两个点就不处在同一个现有已经处理过的奇环中,我们就需要将其缩为一个点(或者说是一朵花),并且把上面的奇点全都标记为偶点,丢到队列里面拓展。

      这就是带花树的完整做法。不理解的可以结合我的代码理解一下。我就是看别人代码看懂的......

      代码如下:

    //It is made by ljh2000
    #include <iostream>
    #include <cstdlib>
    #include <cstring>
    #include <cstdio>
    #include <cmath>
    #include <algorithm>
    using namespace std;
    typedef long long LL;
    const int MAXN = 520;
    const int MAXM = 250011;
    const int MAXL = 10011;
    int n,m,ecnt,first[MAXN],next[MAXM],to[MAXM],father[MAXN],Tim;
    int dui[MAXL],head,tail,id[MAXN],pre[MAXN],match[MAXN],ans,vis[MAXN];
    inline int find(int x){ if(father[x]!=x) father[x]=find(father[x]); return father[x]; }
    inline int getint(){
        int w=0,q=0; char c=getchar(); while((c<'0'||c>'9') && c!='-') c=getchar();
        if(c=='-') q=1,c=getchar(); while (c>='0'&&c<='9') w=w*10+c-'0',c=getchar(); return q?-w:w;
    }
    
    inline int lca(int x,int y){
    	Tim++;
    	while(vis[x]!=Tim) {
    		if(x) {
    			x=find(x);
    			if(vis[x]==Tim) return x;
    			vis[x]=Tim;
    			if(match[x]!=0)	x=find(pre[match[x]]);
    			else x=0;
    		}
    		swap(x,y);
    	}
    	return x;
    }
    
    inline void change(int x,int y,int k){//把奇环上的点缩成一个点,并且把原来是奇点的点变成偶点,加入队列
    	while(find(x)!=k) {
    		pre[x]=y; int z=match[x];
    		if(id[z]==1) { id[z]=0; dui[++tail]=z; }
    		if(find(z)==z) father[z]=k;
    		if(find(x)==x) father[x]=k;
    		y=z; x=pre[y];
    	}
    }
    
    inline bool bfs(int ini){
    	for(int i=1;i<=n;i++) id[i]=-1,father[i]=i;
    	head=tail=0; dui[++tail]=ini; id[ini]=0; int u;
    	while(head<tail) {
    		u=dui[++head]; 
    		for(int i=first[u];i;i=next[i]) {
    			int v=to[i]; 
    			if(id[v]==-1) {
    				pre[v]=u; id[v]=1;
    				if(!match[v]) {
    					int last,t,now=v;
    					while(now!=0) {
    						t=pre[now]; last=match[t];
    						match[t]=now; match[now]=t;
    						now=last;
    					}
    					return true;
    				}
    				id[match[v]]=0; dui[++tail]=match[v];
    			}
    			else if(id[v]==0&&find(u)!=find(v)){ //出现奇环且不是在同一个环中
    				int g=lca(u,v);
    				change(u,v,g);
    				change(v,u,g);
    			}
    		}
    	}
    	return false;
    }
    
    inline void work(){
    	n=getint(); m=getint(); int x,y;
    	for(int i=1;i<=m;i++) {
    		x=getint(); y=getint();
    		next[++ecnt]=first[x]; first[x]=ecnt; to[ecnt]=y;
    		next[++ecnt]=first[y]; first[y]=ecnt; to[ecnt]=x;
    	}
    	for(int i=1;i<=n;i++) if(!match[i]&&bfs(i)) ans++;
    	printf("%d
    ",ans);
    	for(int i=1;i<=n;i++) printf("%d ",match[i]);
    }
    
    int main()
    {
        work();
        return 0;
    }
    

      

      

  • 相关阅读:
    STL map用法总结(multimap)
    Ice Cream Tower
    位运算 进制转化 STL中bitset用法
    《算法导论》插入排序
    C++输入/输出流
    kuangbin大佬模板(侵删)- hdu 2222
    poj 3461
    动态规划入门-01背包问题
    Dropping water balloons (入门dp)
    TSP
  • 原文地址:https://www.cnblogs.com/ljh2000-jump/p/6254234.html
Copyright © 2011-2022 走看看