KM算法
时间:2019-08-21
本文章向大家介绍KM算法,主要包括KM算法使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。
用途:求出带权二分图的最大权匹配
流程:
1. 把左边每个点的顶标设为与它相连的边中最大的权值,右边每个点顶标设为\(0\)。
2. 对于每个点\(i\),进行步骤\(3\)。
3. 在与\(i\)相连的所有边中找到一条边\((i,u)\)使得\(w(i,u)=val(i)+val(u)\),如果\(u\)未匹配则匹配\(i\)和\(u\),进入步骤\(4\);如果\(u\)已匹配则对\(u\)重复步骤\(3\)。都找完后进入步骤\(4\)。
4. 若找到了满足条件的点\(u\),则匹配\(i\)和\(u\),重复步骤\(2\)。若没有找到,进入步骤\(5\)。
5. 把上次的\(3\)操作中涉及的所有左边点顶标\(-1\),右边点顶标\(+1\),重复步骤\(3\)。
代码:
#include<bits/stdc++.h>
using namespace std;
int n,m,e;
int array[1001][1001];//邻接存图
int match[1001];//匹配
int value_left[1001];//左点顶标
int value_right[1001];//右点顶标
int visit_left[1001];//左点标记
int visit_right[1001];//右点标记
int ans;
inline int 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<<1)+(x<<3)+(ch^48);
ch=getchar();
}
return x*f;
}
int augment(int x){//增广操作(步骤3)
visit_left[x]=1;//给涉及的点打标记
for(int i=1;i<=m;i++){//遍历每一条边
if(!visit_right[i]&&value_right[i]+value_left[x]==array[x][i]){//如果i此次未被涉及过且满足条件
visit_right[i]=1;//涉及i
if(match[i]==-1||augment(match[i])){//如果i未被匹配
match[i]=x;//把i与x匹配
return 1;//返回成功
}
}
}
return 0;//如果一个都不行,返回失败
}
int main(){
memset(match,-1,sizeof match);
n=read();
m=read();
e=read();
for(int i=1;i<=e;i++){
int u,v,w;
u=read();
v=read();
w=read();
array[u][v]=w;
}
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){//处理左点顶标
value_left[i]=max(value_left[i],array[i][j]);
}
}
for(int i=1;i<=n;i++){//每次记得清空标记
memset(visit_left,0,sizeof visit_left);
memset(visit_right,0,sizeof visit_right);
while(!augment(i)){//对于一个点如果增广不成功就不停重复
for(int j=1;j<=n;j++){//如果左点被访问则-1
value_left[j]-=visit_left[j];
}
for(int j=1;j<=m;j++){//如果右点被访问则+1
value_right[j]+=visit_right[j];
}
memset(visit_left,0,sizeof visit_left);
memset(visit_right,0,sizeof visit_right);
}
}
for(int i=1;i<=m;i++){//统计匹配的答案
if(match[i]!=-1)ans+=array[match[i]][i];
}
cout<<ans;
return 0;
}
原文地址:https://www.cnblogs.com/xiong-6/p/11391575.html
- rpc框架之 thrift 学习 2 - 基本概念
- rpc框架之avro 学习 1 - hello world
- 探讨Android中的内置浏览器和Chrome
- java并发编程学习: 阻塞队列 使用 及 实现原理
- CSS魔法堂:说说Float那个被埋没的志向
- Netbeans配置Xdebug
- rpc框架: thrift/avro/protobuf 之maven插件生成java类
- WebComponent魔法堂:深究Custom Element 之 从过去看现在
- 数据可视化-EChart2.0使用总结1
- JavaScript事件概览
- gradle项目与maven项目相互转化
- rpc框架之gRPC 学习 - hello world
- Angular Service入门
- spring:如何用代码动态向容器中添加或移除Bean ?
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- Linux 常见文件管理命令及目录结构(1)
- Java parseInt( ) 方法
- 详解 Vue 目录及配置文件之 node_modules,src,static,test 目录
- 洛谷 P1077 摆花(记忆化搜索 or DP)
- Vue 使用 element-ui
- Codeforces Round #629 (Div. 3) F. Make k Equal (技巧暴力,类前缀和,思维,数学)
- vue 渐变色文字
- Java 水题系列(2)Pi的近似值
- vue 无缝滚动组件 vue-seamless-scroll
- Java 水题系列(3)回文素数
- NDB Cluster 8.0中的自动模式同步:第1部分
- MongoDB助力一个物流订单系统
- NDB Cluster 8.0中的自动模式同步:第2部分
- NetCore配置框架详解
- 初识ABP vNext(11):聚合根、仓储、领域服务、应用服务、Blob储存