• [模板] 匈牙利算法&&二分图最小字典序匹配


    匈牙利算法

    简介

    匈牙利算法是一种求二分图最大匹配的算法.

    时间复杂度: 邻接表/前向星: (O(n * m)), 邻接矩阵: (O(n^3)).
    空间复杂度: 邻接表/前向星: (O(n + m)), 邻接矩阵: (O(n^2)).

    它的主要思路就是对每个点寻找增广路, 尝试改变之前的选择, 判断是否可行.

    事实上, 利用dinic/isap跑二分图有 (O(n * sqrt{m})) 的优秀复杂度(不会证), 因此匈牙利算法仅用于少数特殊情况↓

    代码

    int to[nsz][nsz]; //邻接表
    int vi[nsz],mat[nsz];
    bool arg(int p){
    	rep(i,1,to[0]){
    		int v=to[p][i];
    		if(vi[v])continue;
    		vi[v]=1;
    		if(mat[v]==0||arg(mat[v])){
    			mat[v]=p,mat[p]=v;
    			return 1;
    		}
    	}
    	return 0;
    }
    
    int hung(){
    	int res=0;
    	repdo(i,1,n){
    		memset(vi,0,sizeof(vi));
    		res+=arg(i);
    	}
    	return res;
    }
    

    二分图最小字典序匹配

    简介

    这就是上面说的特殊情况:P

    考虑匈牙利算法的过程: 将每一个点尝试增广, 同时改变之前的点的匹配.

    因此, 我们可以考虑将所有点的出边按标号排序, 逆向遍历每一个点, 并按标号顺序尝试增广.
    显然, 第一个点的匹配一定是它能匹配到的最小标号, 第二个点的匹配是满足第一个点时的最小标号, 以此类推.

    代码

    //[NOI2009] 变换序列
    int to[nsz][3];
    int vi[nsz],mat[nsz];
    bool arg(int p){
    	rep(i,0,1){
    		int v=to[p][i];
    		if(vi[v])continue;
    		vi[v]=1;
    		if(mat[v]==0||arg(mat[v])){
    			mat[v]=p,mat[p]=v;
    			return 1;
    		}
    	}
    	return 0;
    }
    
    int hung(){
    	int res=0;
    	repdo(i,n-1,0){
    		memset(vi,0,sizeof(vi));
    		res+=arg(i);
    	}
    	return res;
    }
    

    参考资料

  • 相关阅读:
    JAVA设计模式---总述篇
    Java中对象创建时的内存分配
    for循环打印空心菱形的新方法
    springcloud2.X通过actuator加载配置无效问题
    golang-错误处理
    golang-字符串
    golang-方法和接口
    golang-结构体与指针
    golang-数组、切片、映射
    golang-流程控制
  • 原文地址:https://www.cnblogs.com/ubospica/p/10249693.html
Copyright © 2020-2023  润新知