二分图匹配 Hopcroft-Carp (HK) 算法详解 附例题
了解这个算法之前 首先了解一个概念 :增广路
增广路 :简单的说 ,是二分图匹配中的一条边,他总是从 左边集合的一个点出发通过一条没有被匹配的边连接到右边集合,再从该点通过一条 匹配过的边连接到右边集合。
图1为 正常的二分图
图2为二分图的最大匹配
图3 为二分图最大匹配中的增广路 两条 紫色一条 黄色一条。
了解这个算法之前,还需要对一个算法进行比较: 匈牙利算法
匈牙利算法 如果用增广路来说明的话,就是从一个点出发,如果找到一个匹配 就连接这个匹配。
如果当前这个点 被匹配过的话,就去寻找一个增广路,找到左边集合中的点,看该点是否还能匹配到 右边集合的点 匹配到最后 增广路的长度为 2*n,最终无法匹配。
简单的说就是,每次判断能匹配就匹配,匹配不到就去寻找一个增广路使他继续匹配。
这样的复杂度 O(N*M)
如果数据太大,会爆TLE,所以HK算法将其复杂度优化 -> O(sqrt(n)*m)
再者:了解HK算法的本质:是对匈牙利的算法的优化,匈牙利算法一次只更新一条增广路,而HK算法,同时更新多条互不相交的最短增广路。
经证明 :当更新到sqrt(n)的时候,最大匹配已被全部OK。复杂度证明 自行搜索。
然后开始正经的 算法讲解(一定要了解本质是对匈牙利算法的优化):
所以根据 优化这条性质出手
第一步:他需要找到当前最短的匹配 找不到就去找最短的增广路
左边第一个点 链接到 右边第一个点 发现右边第一个点未匹配 ,那么就连起来 更新当前最短的路程
如果发现右边的点匹配过,那么就去寻找 一条增广路,用BFS实现。
比如上图中:第一次 左1连接右3,左2连接右2,左4连接右4 这是长度为1的匹配.
第二次更新:左边只有第三个点还未进行匹配,所以用第三个点更新,左3连右2,右2已经被标记过了,那么找到右2的归属者:左2,对左2进行 搜索发现可以去连接到右3,所以当前的匹配长度为3,所以继续寻找匹配,用匈牙利算法递归进行匹配即可。
这一部分的代码总结为:
/****
前期数组定义(一遍):
nR :标记右边集合的点是否被标记
nL :标记左边集合的点是否被标记
dR : 更新当前增广路的距离,也便于更新
dL :同上
****/
bool judge()// 更新当前最短的增广路
{memset(dR,-1,sizeof(dR));//初始化的意思是 :因为多条增广路互不相交,所以一旦发生变化,另一个就不能再去标记了。memset(dL,-1,sizeof(dL));dis=INF;queue<int>q;for(int i=1;i<=n;i++) {if(nL[i]==-1){q.push(i);dL[i]=0;}}while(!q.empty()){int u=q.front();q.pop();if(dL[u]>dis) break;//保证最短长度的赠广路for(int i=1;i<=m;i++){if(mp[u][i]<=t&&dR[i]==-1)//dR[i]!=-1 保证所有增广路都不相交{dR[i]=dL[u]+1;if(nR[i]==-1) dis=dR[i]; //如果当前点没有被标记 ,那么可以匹配到else//否则找到他的归属者,用归属者进入队列 ,寻找增广路{dL[nR[i]]=dR[i]+1;q.push(nR[i]);}}}}return dis!=INF;//只要能找到增广路 dis就不为INF
}
第二步:我们匹配完多条增广路之后,我们就用匈牙利的思想就去更新,这多条增广路,也是遍历左边集合中没有匹配到的点,看他们是否可以通过一条增广路匹配到,但会出现一个问题: 会增加时间,例如:
如果一个点 已经被匹配到 ,并且他是最后一个匹配的节点,那么这个节点连过去之后一定不可能成为增广路。所以不需要判断否则会耽误很多时间:
bool Find(ll x)
{for(int i=1;i<=m;i++){if(!vis[i]&&mp[x][i]<=t&&dL[x]+1==dR[i]){vis[i]=1;if(nR[i]!=-1&&dR[i]==dis) continue; //特判一下if(nR[i]==-1||Find(nR[i]))//找到就匹配,找不到就匹配他的父辈节点{nR[i]=x;nL[x]=i;return true;}}}return false;
}
第三步:进行最大匹配就可以了。结束条件是 找不到增广路:
ll MaxMatch()
{ll cnt=0;while(judge()){for(int i=1;i<=n;i++){for(int k=1;k<=m;k++) vis[k]=false;if(nL[i]==-1)if(Find(i)) cnt++;}}return cnt;
}
最后附加一个例题:
Rain on your Parade POJ的一个题:可以去搜搜
AC:
#include<bits/stdc++.h>
#define ll long long
#include <stdio.h>
#include <algorithm>
#pragma GCC optimize(2)
using namespace std;
const int maxn=1e6+1000;
const ll INF=10000000000;
inline ll read()
{int x=0,f=1;char ch=getchar();while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}return x*f;
}ll n,m;
ll dis;
double t;
bool vis[5000];
int nR[5000],nL[5000];
int dR[5000],dL[5000];
struct node{double x,y;double v;
}gest[5000],umb[5000];
double cal(node a,node b)
{return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y));
}
bool judge()// 更新当前最短的增广路
{memset(dR,-1,sizeof(dR));memset(dL,-1,sizeof(dL));dis=INF;queue<int>q;for(int i=1;i<=n;i++) {if(nL[i]==-1){q.push(i);dL[i]=0;}}while(!q.empty()){int u=q.front();q.pop();if(dL[u]>dis) break;//保证最短长度的赠广路for(int i=1;i<=m;i++){if((cal(umb[i],gest[u])/gest[u].v)<=t&&dR[i]==-1)//dR[i]!=-1 保证所有增广路都不相交{dR[i]=dL[u]+1;if(nR[i]==-1) dis=dR[i];else{dL[nR[i]]=dR[i]+1;q.push(nR[i]);}}}}return dis!=INF;
}
bool Find(ll x)
{for(int i=1;i<=m;i++){if(!vis[i]&&(cal(umb[i],gest[x])/gest[x].v)<=t&&dL[x]+1==dR[i]){vis[i]=1;if(nR[i]!=-1&&dR[i]==dis) continue;if(nR[i]==-1||Find(nR[i])){nR[i]=x;nL[x]=i;return true;}}}return false;
}
ll MaxMatch()
{ll cnt=0;while(judge()){for(int i=1;i<=n;i++){for(int k=1;k<=m;k++) vis[k]=false;if(nL[i]==-1)if(Find(i)) cnt++;}}return cnt;
}
void restart()
{memset(nR,-1,sizeof(nR));memset(nL,-1,sizeof(nL));
}
int main()
{int T;scanf("%d",&T);int cas=0;bool f=false;while(T--){restart();scanf("%lf",&t);scanf("%lld",&n);for(int i=1;i<=n;i++) scanf("%lf%lf%lf",&gest[i].x,&gest[i].y,&gest[i].v);scanf("%lld",&m);for(int i=1;i<=m;i++) scanf("%lf%lf",&umb[i].x,&umb[i].y);printf("Scenario #%d:\n%lld\n\n",++cas,MaxMatch());}return 0;
}
PS:还是注意 优化那个 如果当前节点被标记过并且是最后一个 匹配点,该条路就一定不能成为增广路!
二分图匹配 Hopcroft-Carp (HK) 算法详解 附例题相关推荐
- python直线拟合_RANSAC算法详解(附Python拟合直线模型代码)
之前只是简单了解RANSAC模型,知道它是干什么的.然后今天有个课程设计的报告,上去讲了一下RANSAC,感觉这个东西也没那么复杂,所以今天就总结一些RASAC并用Python实现一下直线拟合. RA ...
- 数学规划详解(附例题及部分Python实现)
数学规划详解(附例题及Python实现) 例题来自于清风老师的数学建模课,个人认为讲的非常好,欢迎大家购买 一.概述 1.1 定义 数学规划是运筹学的一个分支,在约束条件下,按照目标函数来寻求计划管理 ...
- 关键点匹配——商汤loFTR算法详解与论文解读
论文地址:https://openaccess.thecvf.com/content/CVPR2021/papers/Sun_LoFTR_Detector-Free_Local_Feature_Mat ...
- DFS (深度优先搜索) 算法详解 + 模板 + 例题,这一篇就够了
深度优先搜索算法(Depth First Search,简称DFS):一种用于遍历或搜索树或图的算法. 沿着树的深度遍历树的节点,尽可能深的搜索树的分支.当节点v的所在边都己被探寻过或者在搜寻时结点不 ...
- 数据结构-数组-字符串匹配:Knuth-Morris-Pratt算法(详解附完整代码)
字符串匹配 字符串抽象数据类型 字符串模式匹配 简单的字符串匹配 Knuth-Morris-Pratt算法 背景分析 失配函数 定义 实现方法 函数分析 KMP函数 实现方法 函数分析 失配信息的另一 ...
- dijkstra算法详解加例题分析 NOIP 2012 文化之旅
首先说一下什么叫单源最短路径问题: 给定一个带权有向图G=(V,E),其中每条边的权是一个实数.另外,还给定V中的一个顶点,称为源.现在要计算从源到其他所有各顶点的最短路径长度.这里的长度就是指路上各 ...
- 迪杰斯特拉算法详解+模版+例题
迪杰斯特拉算法(Dijkstra)是由荷兰计算机科学家狄克斯特拉于1959 年提出的,因此又叫狄克斯特拉算法.是从一个顶点到其余各顶点的最短路径算法,解决的是有权图中最短路径问题.迪杰斯特拉算法主要特 ...
- 并查集-算法详解及例题(最小生成树问题)
一.并查集的概念: 并查集(Union-find Sets)是一种非常精巧而实用的数据结构,它主要用于处理一些不相交集合的合并问题.一些常见的用途有求连通子图.求最小生成树的 Kruskal 算法和求 ...
- 多目标跟踪(MOT)中的卡尔曼滤波(Kalman filter)和匈牙利(Hungarian)算法详解
多目标跟踪(MOT)中的卡尔曼滤波(Kalman filter)和匈牙利(Hungarian)算法详解 1. 概览 在开始具体讨论卡尔曼滤波和匈牙利算法之前,首先我们来看一下基于检测的目标跟踪算法的大 ...
最新文章
- jQuery的选择器
- java wed登录面 代码_java web 登录界面
- diou diou_nms代码分享
- 快速搭建 Serverless 人脸识别离线服务
- 1、MySQL 8.0.20最新版本在Linux上安装
- vuejs构建的单页面应用history模式子页面微信分享在iOS中遇到的问题
- Google Chrome 总提示flash插件过期,用命令行模式解决
- linux 脚本 整数 赋值,shell基础!!熟悉编程规范与变量
- 18复变函数的积分(四)
- SpringMVC, Spring和Mybatis整合案例一
- thinkphp5.x之Collection(集合)解析 php集合
- MySql处理Unicode字符串
- HTML5七夕情人节表白网页制作【爱情树-Html5实现唯美表白动画代码】HTML+CSS+JavaScript浪漫告白 求婚必备
- 在微软工作有多舒服?
- FLUX-TMS-物流整体解决方案 附下载地址
- 量子计算机原理 纠缠,白话量子计算机原理【前面的那个有错误,重新理清了一下思路】...
- TypeWriter: Neural Type Prediction with Search-based Validation基于搜索的神经网络预测器
- python selenium学习之新浪微博
- “展厅三维全景”技术,将产品和企业文化以vr展示出来
- 华虹技通华为鸿蒙,浩丰科技(300419)个股分析_牛叉诊股_同花顺财经
热门文章
- 实习每日总结_20161214
- 配置Exchange Server 2010多种邮件客户端收发电子邮件
- 分享一些前端开发人员必备的工具,脚本和资源
- Docker神器之百度云下载(群辉 LEDE)
- Oracle账号怎么注销,qq账号如何永久注销?qq账号永久注销的条件以及详细操作方法...
- LaTex 在图片上添加文字和公式
- C Primer Plus第六版第五章运算符,表达式,语句源码
- 安卓GB28181设备语音广播和语音对讲(Android GB28181 语音广播和语音对讲)实现
- 做好软件测试的关键是什么,做好测试计划和测试用例的工作的关键是什么?
- JAVA数独解题(四):数对法