【数据关联】简记——匈牙利DFS

数据关联或者数据匹配的方法有:匈牙利算法、最近邻关联算法、回溯法等,当然还有很多其他的算法~

一、匈牙利算法:是一种在多项式时间内求解任务分配问题的组合优化算法。

基本概念如下:

(1)寻找交替路:从一个未匹配点出发,依次经过非匹配边、匹配边、非匹配边...形成的路径叫交替路。

(2)寻找增广路:从一个未匹配点出发,走交替路,如果途径另一个未匹配点(出发的点不算),则这条交替路称为增广路(agumenting path)。

匈牙利算法就是在不断寻找增广路,如果找不到增广路,就说明达到了最大匹配。

举个栗子:参考匈牙利算法(二分图) - 神犇(shenben) - 博客园

1.起始未匹配(匹配都从同一向的点开始,如x的点)

【数据关联】简记——匈牙利DFS_第1张图片

2.由x1开始寻找匹配  

【数据关联】简记——匈牙利DFS_第2张图片                                   

3.再到x2寻找匹配  

【数据关联】简记——匈牙利DFS_第3张图片

4.到x3进行匹配。但是x3可以匹配的第一个点被x1占用了,此时先寻找x3的交替路x3-y1-x1-y4,把交替路中原来已经匹配的x1y1的取消。改为x1与y4匹配

【数据关联】简记——匈牙利DFS_第4张图片

5.同理,寻找后续未进行匹配的点。

         匈牙利可以使用DFS(深度优先搜索)和BFS(广度优先搜索)来实现,上述例子使用的DFS,寻找到的是最大匹配。匈牙利还可以找到最优匹配、最小点覆盖等,还有带权重的KM算法。此处不作赘述。

匈牙利DFS代码实现(此处使用递归实现,也可以使用栈实现):参考算法学习笔记(5):匈牙利算法 - 知乎

int M, N;            //M, N分别表示左、右侧集合的元素数量
int Map[MAXM][MAXN]; //邻接矩阵存图
int p[MAXN];         //记录当前右侧元素所对应的左侧元素
bool vis[MAXN];      //记录右侧元素是否已被访问过
bool match(int i)
{
    for (int j = 1; j <= N; ++j)
        if (Map[i][j] && !vis[j]) //有边且未访问
        {
            vis[j] = true;                 //记录状态为访问过
            if (p[j] == 0 || match(p[j])) //如果暂无匹配,或者原来匹配的左侧元素可以找到新的匹配
            {
                p[j] = i;    //当前左侧元素成为当前右侧元素的新匹配
                return true; //返回匹配成功
            }
        }
    return false; //循环结束,仍未找到匹配,返回匹配失败
}
int Hungarian()
{
    int cnt = 0;
    for (int i = 1; i <= M; ++i)
    {
        memset(vis, 0, sizeof(vis)); //重置vis数组,每进行一次搜索都要重置
        if (match(i))
            cnt++;//记录匹配上的数目
    }
    return cnt;
}

 小结:此处的匈牙利DFS是为了找到最大匹配,如果已经找到了最大匹配就会跳出递归,即使还会有其他的匹配方式也不会再寻找,默认使用当前找到匹配方式。虽然匈牙利DFS找到了最大的匹配,但不一定是最优的匹配方式,所以还可以结合其他的算法得到最优的匹配方式,后续讲匈牙利DFS与全局最近邻关联(GNN)算法的结合得到最优匹配。当然匈牙利KM算法也可以得到最优匹配。

二、DFS(深度优先搜索算法):一种用于遍历或搜索树或图的算法。 沿着树的深度遍历树的节点,尽可能深的搜索树的分支。当节点v的所在边都己被探寻过或者在搜寻时结点不满足条件,搜索将回溯到发现节点v的那条边的起始节点。整个进程反复进行直到所有节点都被访问为止。

 【数据关联】简记——匈牙利DFS_第5张图片

 DFS的基本代码模板如下:参考C语言 DFS(深度优先搜索算法) 详解_伏城无嗔的博客-CSDN博客_c语言dfs算法

int check(参数)
{
    if(满足条件)
        return 1;
    return 0;
}
 
void dfs(int step)
{
        判断边界
        {
            相应操作
        }
        尝试每一种可能
        {
               满足check条件
               标记
               继续下一步dfs(step+1)
               恢复初始状态(回溯的时候要用到)
        }
} 

 小结:此处DFS也是采用递归实现的,与匈牙利的DFS类似,不同之处是匈牙利DFS只寻找到一种最大匹配就会结束寻找,此时的最大匹配不一定是最优的,也有可能是最优的;而DFS则会遍历各种匹配方式,但是如果不加入其他的条件加以辅助找到最优的匹配,那么它将输出最后一种匹配方式。所以加入全局最近邻关联(GNN)算法使得从DFS的各种匹配中找到最优的匹配。

三、DFS与全局最近邻算法(GNN)

  1. 首先是使用DFS寻找各种匹配方式(不是匈牙利DFS),记录各个匹配对
  2. 然后根据各个匹配对的关联度来是否是最优匹配,选择最优匹配的前提可以是当前的匹配是最大的匹配
  3. 最后将最优匹配的匹配对输出

四、递归

参考:关于递归前后语句执行顺序_HoryC的博客-CSDN博客_递归代码执行顺序

解释循环中的递归调用_冰凌其的博客-CSDN博客_循环递归调用

小结:递归前后都有代码,且递归位于循环中:先执行位于递归前的代码,然后将当前循环中位于递归后的代码先压栈,再将后面循环的代码压栈;当递归到出口后,先执行最后压栈的代码,再执行前面压栈的代码,秉承先进后出原则继续进行递归。

你可能感兴趣的:(算法原理,算法,图搜索算法,近邻算法,深度优先)