• 学习笔记 匈牙利算法


    匈牙利算法是一种精妙的算法,我一开始都不敢相信他是对的。

    先来看定义:

    • 匹配 匹配是一个边集,其中任意两条边都没有公共端点。
    • 最大匹配 顾名思义,包含边数最多的匹配
    • 交错路 匹配边和非匹配边依次出现的一条路
    • 增广路 从非匹配边出发,以非匹配边结束的交错路(增广路长度一定是奇数)

    感觉好奇怪啊

    匈牙利算法的基本思想,就是不断地扩大匹配的集合,不断尝试让匹配边数加一。匹配边数不能变多了,算法也就结束了。

    有两条性质,乍一看很显然,其实很难证:

    • 一个匹配(M)是最大匹配,当且仅当图中不存在增广路。
    • 从某一点(左部点)出发,如果某个时刻找不到增广路,那就永远都找不到了。

    性质1的必要性是显然的,让我们先来看算法的过程。

    我们首先给二分图定向(说人话就是划分出左部和右部,规定增广路从左部出发)。枚举每一个左部点(是非匹配点),如果能找到增广路,我们就把增广路上所有边的状态取反,得到一种大小+1的匹配。
    复杂度(O(nm)) (点数*边数)

    结合代码理解一下

    int vis[mxn],mch[mxn];//match
    inline bool hungary(int x){
        if(vis[x])return 0;vis[x]=1;
    //vis记录左部点右部点皆可
        for(int i=first[x];i;i=nxt[i]) //边是单向边
            if(!mch[to[i]] || hungary(mch[to[i]]))return mch[to[i]]=x,1;
        return 0;
    }
    
    //main函数
    int ans=0;
    for(int i=1;i<=n;++i)memset(vis,0,sizeof(vis)),ans+=hungary(i);
    
    

    我们回过头看这两个性质,性质1是算法的基础,性质2确保了每个点只搜一次。

    对证明感兴趣的可以看队爷论文,写的可好了,适合初学者看。

    可以再看看 hall定理 虽然本文没有用到

    好像还能用bfs写,据说常数更小。

    以上。

  • 相关阅读:
    linux 挂载 smb
    lvds(800*600)
    uart测试代码
    Linux下SPI测试程序
    Adding Flexcan driver support on Kernel
    在freescale mx6q平台上添加spi资源
    I.MX6Q(TQIMX6Q/TQE9)学习笔记——内核启动与文件系统挂载
    Android实现AppWidget、Broadcast静态注册
    Android实现AppWidget、Broadcast动态注册
    Android实现页面跳转、ListView及其事件
  • 原文地址:https://www.cnblogs.com/happyguy/p/13485224.html
Copyright © 2020-2023  润新知