带权二分图最大匹配KM算法
二分图的判定
如果一个图是连通的,可以用如下的染色法判定是否二分图:
我们把
X
部的结点颜色设为0
,Y
部的颜色设为1
。从某个未染色的结点
u
开始,做BFS
或者DFS
。把u
染为0
,枚举u
的儿子v
。如果v
未染色,就染为与u
相反的颜色,如果已染色,则判断u
与v
的颜色是否相同,相同则不是二分图。如果一个图不连通,则在每个连通块中作判定。
#include <bits/stdc++.h>
const int maxn = 505;
std::vector<int> e[maxn];
int m,n,color[maxn];
bool flag;//全局,标记是否有环
void dfs(int u){
if(flag) return;//如果已经存在环就没必要接着递归了
int len = e[u].size();//省点常数
for(int i = 0; i < len; i++){ //遍历所有相邻顶点,即连着的点
int v = e[u][i];
if(color[v]==0){//v还未访问,染色并递归
color[v] = -color[u];
dfs(v);
}
else if(color[v]==color[u]){
flag=1;//说明有环
return;
}
}
} void solve(){
for(int i = 0; i < n; i++){
if(color[i] == 0){
color[i] = 1;
dfs(i);
if(flag){
printf("NOT BICOLORABLE.\n");
return;
}
}
}
printf("BICOLORABLE.\n");
}
int main(){
while(~scanf("%d%d",&n,&m)){
memset(color, 0, sizeof(color));
memset(e, 0, sizeof(e));
for(int i = 0; i < m; i++){
int u,v;scanf("%d%d",&u,&v);
e[u].push_back(v);e[v].push_back(u);
}
solve();
}
return 0;
}
最大匹配KM
算法
顶标:设顶点 \(X_i\) 的顶标为 \(A[i]\),顶点 \(Y_j\) 的顶标为 \(B[j]\) ,顶点 \(X_i\) 与 \(Y_j\) 之间的边权为 \(w[i][j]\),初始化时,\(A[i]\) 的值为与该点关联的最大边权值,\(B[j]\) 的值为
0
相等子图:选择 \(A[i] + B[j] = w[i][j]\) 的边 \(<i, j>\) 构成的子图,就是相等子图。
算法执行过程中,对任一条边\(<i, j>\) ,\(A[i] + B[j] >= w[i][j]\) 恒成立。
slack
数组存的数是Y
部的点相等子图时,最小要增加的值算法图示:
从\(X_1\) 开始跑匈牙利,匹配的条件是:\(A[i] + B[j] = w[i][j]\) ,显然 $ X_1$ 和 \(Y_3\) 匹配成功。
接着从 \(X_2\) 开始,\(A[X_2]+B[Y_3]==w[X_2][X_3]\) ,此时 \(Y_3\) 已被 \(X_1\) 匹配,尝试让 \(X_1\) 换一个匹配对象,但在 \(X_1\) 的邻接点没有满足:\(A[i] + B[j] = w[i][j]\) 的点,这些相临边和顶标和的最小差值为:\(minz=1\) ,把此时已标记的 \(X\) 部的顶标减去\(minz\),即:\(A[x_1]=5-1=4,A[X_2]-1=3\) , \(Y\) 部的此时标记的顶标加上\(minz\),即:\(B[y_3]=0+1=1\) ,此时\(A[X_1]+B[Y_1]==w[X_1][Y_1]\)。
最后从\(X_3\) 开始找增广路,\(X_3\) 匹配 \(Y_3\) ,不满足,调整顶标,即\(A[3]=5-1=4\),匹配\(Y_3\) 成功,尝试劝说 \(X_2\) 寻找新的匹配,此时 \(Y_1\) 满足匹配,尝试让 \(X_1\) 寻找新的匹配,此时\(X_1\)已找不到新的为匹配的点,匹配失败,回溯到 \(X_2\) ,
Code
#include <bits/stdc++.h>
const int maxn = 300 + 10,maxe=1e4+5,Inf = 0x3f3f3f3f;
struct Edee{int to,w,next;}e[maxe];
int n,m,len,head[maxn],g[maxn][maxn];
int wx[maxn], wy[maxn];//每个点的顶标值(需要根据二分图处理出来)
int match[maxn];//每个Y部点所匹配的X部的点
int visx[maxn], visy[maxn];//每个点是否加入增广路
int slack[maxn];//边权和顶标最小的差值
void Insert(int u,int v){
e[++len].to=v;e[len].next=head[u];head[u]=len;
}
bool dfs(int u){//进入DFS的都是X部的点,找到增光路返回1,否则返回0
visx[u] = 1;//标记进入增广路
for(int i = head[u]; i ; i=e[i].next){
int v = e[i].to;
if(!visy[v]){//如果Y部的点还没进入增广路,并且存在路径
int t = wx[u] + wy[v] - g[u][v];
if(t == 0){//t为0说明是相等子图
visy[v] = 1;//加入增广路
if(match[v] == -1 || dfs(match[v])){
match[v] = u;//进行匹配
return 1;
}
}
else if(t > 0)//此处t一定是大于0,因为顶标之和一定>=边权
slack[v] = std::min(slack[v], t);
//slack[v]存的是Y部的点需要变成相等子图顶标值最小增加多少
}
}
return false;
} int KM(){
memset(match, -1, sizeof(match));
memset(wx, 0, sizeof(wx));//wx的顶标为该点连接的边的最大权值
memset(wy, 0, sizeof(wy));//wy的顶标为0
for(int u = 1; u <= n; u++){//预处理出顶标值
for(int i = head[u]; i ; i=e[i].next)
wx[u] = std::max(wx[u], g[u][e[i].to]);
}
for(int i = 1; i <= n; i++){//枚举X部的点
memset(slack, 0x3f, sizeof(slack));
while(1){
memset(visx, 0, sizeof(visx));
memset(visy, 0, sizeof(visy));
if(dfs(i))break;//已经匹配正确
int minz = Inf;
for(int j = 1; j <= n; j++)
if(!visy[j] && minz > slack[j])
minz = slack[j];//找出还没经过的点中,需要变成相等子图的最小额外增加的顶标值
//将X部已访问的顶标减去minz,Y部已访问的顶标加上minz
for(int j = 1; j <= n; j++)
if(visx[j])wx[j] -= minz;
for(int j = 1; j <= n; j++)
//修改顶标后,要把所有不在交错树中的Y顶点的slack值都减去minz
if(visy[j])wy[j] += minz;
else slack[j] -= minz;//未在增光路,但相应的X部已访问的顶标减少了,其相邻的未访问的期望也减小
}
} int ans = 0;//二分图最优匹配权值
for(int i = 1; i <= n; i++)
if(match[i] != -1)ans += g[match[i]][i];
return ans;
}
int main(){
while(scanf("%d%d", &n,&m) != EOF){
for(int i = 1; i <= m; i++){
int u,v,w;scanf("%d%d%d", &u,&v,&w);
g[u][v]=w;Insert(u,v);
}
printf("%d\n", KM());
}
return 0;
}
带权二分图最大匹配KM算法的更多相关文章
- UVA1349(带权二分图最大匹配 --> KM算法模板)
UVA1349 题意:给定一些有向带权边,求出把这些边构造成一个个环,总权值最小 解法: 对于带权的二分图的匹配问题可以用通过KM算法求解. 要求最大权匹配就是初始化g[i][j]为0,直接跑就可以: ...
- HDU 2255 奔小康赚大钱(带权二分图最大匹配)
HDU 2255 奔小康赚大钱(带权二分图最大匹配) Description 传说在遥远的地方有一个非常富裕的村落,有一天,村长决定进行制度改革:重新分配房子. 这可是一件大事,关系到人民的住房问题啊 ...
- Luogu 1559 运动员最佳匹配问题(带权二分图最大匹配)
Luogu 1559 运动员最佳匹配问题(带权二分图最大匹配) Description 羽毛球队有男女运动员各n人.给定2 个n×n矩阵P和Q.P[i][j]是男运动员i和女运动员j配对组成混合双打的 ...
- "《算法导论》之‘图’":不带权二分图最大匹配(匈牙利算法)
博文“二分图的最大匹配.完美匹配和匈牙利算法”对二分图相关的几个概念讲的特别形象,特别容易理解.本文介绍部分主要摘自此博文. 还有其他可参考博文: 趣写算法系列之--匈牙利算法 用于二分图匹配的匈牙利 ...
- 运动员最佳匹配问题 KM算法:带权二分图匹配
题面: 羽毛球队有男女运动员各n人.给定2 个n×n矩阵P和Q.P[i][j]是男运动员i和女运动员j配对组成混合双打的男运动员竞赛优势:Q[i][j]是女运动员i和男运动员j配合的女运动员竞赛优势. ...
- POJ 2195 Going Home (带权二分图匹配)
POJ 2195 Going Home (带权二分图匹配) Description On a grid map there are n little men and n houses. In each ...
- POJ 2195 Going Home | 带权二分图匹配
给个地图有人和房子 保证人==房子,每个人移动到房子处需要花费曼哈顿距离的代价 问让人都住在房子里最小代价 显然是个带权二分图最大匹配 转化成以一个网络,规定w是容量,c是代价 1.S向人连边,w=1 ...
- KM(Kuhn-Munkres)算法求带权二分图的最佳匹配
KM(Kuhn-Munkres)算法求带权二分图的最佳匹配 相关概念 这个算法个人觉得一开始时有点难以理解它的一些概念,特别是新定义出来的,因为不知道是干嘛用的.但是,在了解了算法的执行过程和原理后, ...
- 浅谈二分图的最大匹配和二分图的KM算法
二分图还可以,但是我不太精通.我感觉这是一个很烦的问题但是学网络流不得不学它.硬啃吧. 人比较蠢,所以思考几天才有如下理解.希望能说服我或者说服你. 二分图的判定不再赘述一个图是可被划分成一个二分图当 ...
随机推荐
- JZOJ1496 页
Description 战神阿瑞斯听说2008年在中华大地上,将举行一届规模盛大的奥林匹克运动会,心中顿觉异常兴奋,他想让天马在广阔的天空上,举行一场精彩的天马队列变换表演.首先,战神安排n头高度不同 ...
- JUC使用
1.什么是JUC 源码 + 官方文档 面试高频问! java.util 工具包.包.分类 业务:普通的线程代码 Thread Runnable 没有返回值.效率相比入 Callable 相对较低! 2 ...
- shellcode注入原理
我们直接写入可能无法执行 unsigned char data[130] = { 0x55, 0x8B, 0xEC, 0x83, 0xEC, 0x0C, 0xC7, 0x45, 0xF8, 0x00, ...
- Java多线程--公平锁与非公平锁
上一篇文章介绍了AQS的基本原理,它其实就是一个并发包的基础组件,用来实现各种锁,各种同步组件的.它包含了state变量.加锁线程.等待队列等并发中的核心组件,现在我们来看一下多线程获取锁的顺序问题. ...
- Java Web学习(五)session、cookie、token
文章更新时间:2020/09/14 一.引言 动态网页兴起后,会话管理变成开发者需要考虑的一个问题,由于HTTP请求是无状态的,为了区分每个用户,此时引入了会话标识(sessionId)的概念,但是存 ...
- SSH 框架常见错误
新手学习SSH框架的时候总会遇到很多问题,一碰到404 或者500错误就不知道怎么解决. 404错误是很常见的一个错误,如果没有用框架基本上只可能是没有这个路径或者文件,但是用了框架之后404的原因就 ...
- MySQL: 2、SQL语言
一.SQL的简介: 1.SQL的概念: SQL就是结构化查询语言,是一种特殊目的的编程语言,是一种数据库查询和程序设计语言,用于存取数据以及查询.更新和管理关系数据库系统 2.SQL的作用: - ...
- springboot maven项目运行常见报错 及ajax请求报错
如图所示 tomcat运行后直接停止,也不报错 原因:我的原因是controller路径配置重名或者service没有配置@Service 遇见这错找了好久问题,网上也搜不到,特此记录一下 问题2 a ...
- burp suite 之 proxy(代理)
proxy 代理 通过 Options(选项)的edit(编辑) 更改代理的端口号.我的是10086 (不许更改与本机使用端口冲突的端口号) 使用火狐浏览器将代理更改为10086. 抓取火狐浏览器的包 ...
- MATLAB 安装
参考: 链接1 链接2 重要: 1.秘钥:09806-07443-53955-64350-21751-41297 2.在安装目录下替换 bin