二分图最大匹配 -- 匈牙利算法

2024-06-14 15:48

本文主要是介绍二分图最大匹配 -- 匈牙利算法,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!


Algorithm.( Augmenting Path Algorithm )


Input:
    An X-Y bigraph G, a matching M in G,
    and the set U of M-unsaturated vertices in X.
        
Idea:
    Explore M-alternating paths form U,
    letting S ⊆ X and T ⊆ Y be the sets of vertices reached.
    Marks vertices of S that have been explored for path extensions.
    As a vertex is reached, record the vertex from which it is reached.
        
Initialization:
    S = U and T = ∅


Iteration:
    If S has no unmarked vertex,
    stop and report T ∪ ( X - S ) as a minimun cover and M as a maximum matching.
    Otherwise, select an unmarked x ∈ S, consider each y ∈ N( x ) such that xy ∉ M,
    if y is unsaturated, terminate and report an M-augmenting path from U to y.
    Otherwise, y is matched to some w ∈ X by M.
    In this case, include y in T ( reached from x ) and include w in S ( reached from y ).
    After exploring all such edges incident to x, mark x and iterate.


#include <iostream>
#include <cstring>
using namespace std;#define NODE_SIZE 100bool bigraph[NODE_SIZE][NODE_SIZE];
int parent[NODE_SIZE];
bool visit[NODE_SIZE];int num = 0;
int nodes1, nodes2, edges;bool find_augmenting_path( int start_node ){for( int end_node = 1; end_node <= nodes2; ++end_node ){if( bigraph[start_node][end_node] && visit[end_node] == false ){visit[end_node] = true;if( parent[end_node] == 0 ||find_augmenting_path( parent[end_node] ) ){parent[end_node] = start_node;return true;}}}return false;
}int main(){memset( bigraph, false, sizeof( bigraph ) );memset( visit, false, sizeof( visit ) );memset( parent, 0, sizeof( parent ) );cin >> nodes1 >> nodes2 >> edges;for( int i = 1; i <= edges; ++i ){int start_node, end_node;cin >> start_node >> end_node;bigraph[start_node][end_node] = true;}for( int node = 1; node <= nodes1; ++node ){memset( visit, false, sizeof( visit ) );if( find_augmenting_path( node ) )num++;}cout << num << endl;return 0;
}


简单应用:

在 raw * col 的棋盘上,有些格子不能放,用1 * 2 的方块铺棋盘,问能不能铺满?

比如:

思路:

对每种格子着色,黑白相间,不能放的格子除。

然后白色的格子为一个部集,黑色的格子也为一个部集,两个部集进行最大匹配,

若最后匹配数目等于黑色或者白色格子的总数,即为可行;否则,不可行。


法1:

// 1143MS
#include <iostream>
#include <cstring>
#include <vector>
#include <algorithm>
using namespace std;#define CHESSBOARD_SIZE 50
#define GRAPH_SIZE 1100bool chessboard[CHESSBOARD_SIZE][CHESSBOARD_SIZE];
bool bigraph[GRAPH_SIZE][GRAPH_SIZE];
bool visit[GRAPH_SIZE];
int parent[GRAPH_SIZE];
int raws, cols, holes;bool find_augmenting_path( int source ){for( int target = 1; target <= raws * cols; ++target ){if( bigraph[source][target] && !visit[target] ){visit[target] = true;if( parent[target] == 0 || find_augmenting_path( parent[target] ) ){parent[target] = source;return true;}}}return false;
}int maximum_matching(){int ans = 0;for( int i = 1; i <= raws * cols; ++i ){memset( visit, false, sizeof( visit ) );if( find_augmenting_path( i ) )ans++;}return ans;
}int main(){memset( chessboard, false, sizeof( chessboard ) );memset( bigraph, false, sizeof( bigraph ) );memset( visit, true, sizeof( visit ) );memset( parent, 0, sizeof( parent ) );cin >> raws >> cols >> holes;int num = raws * cols;for( int i = 1; i <= holes; ++i ){int raw, col;cin >> col >> raw;chessboard[raw][col] = true;num--;}for( int raw = 1; raw <= raws; ++raw ){for( int col = 1; col <= cols; ++col ){if( chessboard[raw][col] )continue;int p1 = cols * ( raw - 1 ) + col;if( raw > 1 && chessboard[raw - 1][col] == false ){int p2 = p1 - cols;bigraph[p1][p2] = true;}if( raw < raws && chessboard[raw + 1][col]== false ){int p2 = p1 + cols;bigraph[p1][p2] = true;}if( col > 1 && chessboard[raw][col - 1] == false ){int p2 = p1 - 1;bigraph[p1][p2] = true;}if( col < cols && chessboard[raw][col + 1] == false ){int p2 = p1 + 1;bigraph[p1][p2] = true;}}}int ans = maximum_matching();if( ans == num )cout << "YES" << endl;elsecout << "NO" << endl;return 0;
}

法2:

// 725k 32MS
#include <iostream>
#include <vector>
#include <cstring>
using namespace std;#define NODE_SIZE 50struct Position{Position(){raw = -1;col = -1;};Position( int r, int c ){raw = r;col = c;};int raw;int col;
};enum State { INIT, HOLE, BLACK, WHITE };
State chessboard[NODE_SIZE][NODE_SIZE];Position parent[NODE_SIZE * NODE_SIZE];
bool visit[NODE_SIZE * NODE_SIZE];
int raws, cols, holes;int direction[5][3] = {{ 0, 0, 0 },{ 0, 1, 0 },{ 0, 0, 1 },{ 0, -1, 0 },{ 0, 0, -1 }
};bool find_augmenting_path( Position source ){for( int i = 1; i <= 4; ++i ){int dx = direction[i][1];int dy = direction[i][2];int next_raw = source.raw + dx;int next_col = source.col + dy;if( next_raw >= 1 &&next_raw <= raws &&next_col >= 1 &&next_col <= cols ){int one_dim_pos = cols * ( next_raw - 1 ) + next_col;if( chessboard[next_raw][next_col] == WHITE && !visit[one_dim_pos] ){visit[one_dim_pos] = true;if( ( parent[one_dim_pos].raw == -1 &&parent[one_dim_pos].col == -1 ) ||find_augmenting_path( parent[one_dim_pos] ) ){parent[one_dim_pos].raw = source.raw;parent[one_dim_pos].col = source.col;return true;}}}}return false;
}int main(){cin >> raws >> cols >> holes;vector< Position > black_rects;vector< Position > white_rects;for( int raw = 1; raw <= raws; ++raw ){for( int col = 1; col <= cols; ++col ){chessboard[raw][col] = INIT;}}memset( visit, false, sizeof( visit ) );int rects = raws * cols - holes;for( int i = 1; i <= holes; ++i ){int col, raw;cin >> col >> raw;chessboard[raw][col] = HOLE;}for( int raw = 1; raw <= raws; ++raw ){for( int col = 1; col <= cols; ++col ){if( chessboard[raw][col] == HOLE )continue;if( ( col % 2 && raw % 2 ) ||( ( raw % 2 == 0 ) && ( col % 2 == 0 ) ) ){chessboard[raw][col] = BLACK;black_rects.push_back( Position( raw, col ) );}else{chessboard[raw][col] = WHITE;white_rects.push_back( Position( raw, col ) );}}}const int black_rects_num = black_rects.size();const int white_rects_num = white_rects.size();if( black_rects_num == 0 ||rects % 2 != 0 ||black_rects_num != white_rects_num ){cout << "NO" << endl;}else{int ans = 0;for( int i = 0; i < black_rects_num; ++i ){memset( visit, false, sizeof( visit ) );if( find_augmenting_path( black_rects[i] ) )ans++;}if( ans == black_rects_num ){cout << "YES" << endl;}else{cout << "NO" << endl;}}return 0;
}


POJ 3692

建反图,求最大独立集

#include <iostream>
#include <cstring>
using namespace std;#define MAX_SIZE 210bool bigraph[MAX_SIZE][MAX_SIZE];
bool visits[MAX_SIZE];
int parents[MAX_SIZE];
int B, G, M;bool find_augmenting_path( int source ){for( int target = 1; target <= B; ++target ){if( bigraph[source][target] && !visits[target] ){visits[target] = true;if( parents[target] == 0 || find_augmenting_path( parents[target] ) ){parents[target] = source;return true;}}}return false;
}int maximum_matching(){int ans = 0;for( int source = 1; source <= G; ++source ){memset( visits, false, sizeof( visits ) );if( find_augmenting_path( source ) )ans++;}return ans;
}int main(){int nCase = 1;while( true ){memset( bigraph, true, sizeof( bigraph ) );memset( parents, 0, sizeof( parents ) );memset( visits, false, sizeof( visits ) );cin >> G >> B >> M;if( G == 0 && B == 0 && M == 0 )break;for( int i = 1; i <= M; ++i ){int u, v;cin >> u >> v;bigraph[u][v] = false;}int max_matching = maximum_matching();int ans = G + B - max_matching;cout << "Case " << nCase << ": " << ans << endl;nCase++;}return 0;
}


这篇关于二分图最大匹配 -- 匈牙利算法的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1060840

相关文章

Nginx路由匹配规则及优先级详解

《Nginx路由匹配规则及优先级详解》Nginx作为一个高性能的Web服务器和反向代理服务器,广泛用于负载均衡、请求转发等场景,在配置Nginx时,路由匹配规则是非常重要的概念,本文将详细介绍Ngin... 目录引言一、 Nginx的路由匹配规则概述二、 Nginx的路由匹配规则类型2.1 精确匹配(=)2

使用雪花算法产生id导致前端精度缺失问题解决方案

《使用雪花算法产生id导致前端精度缺失问题解决方案》雪花算法由Twitter提出,设计目的是生成唯一的、递增的ID,下面:本文主要介绍使用雪花算法产生id导致前端精度缺失问题的解决方案,文中通过代... 目录一、问题根源二、解决方案1. 全局配置Jackson序列化规则2. 实体类必须使用Long封装类3.

Springboot实现推荐系统的协同过滤算法

《Springboot实现推荐系统的协同过滤算法》协同过滤算法是一种在推荐系统中广泛使用的算法,用于预测用户对物品(如商品、电影、音乐等)的偏好,从而实现个性化推荐,下面给大家介绍Springboot... 目录前言基本原理 算法分类 计算方法应用场景 代码实现 前言协同过滤算法(Collaborativ

Nginx location匹配模式与规则详解

《Nginxlocation匹配模式与规则详解》:本文主要介绍Nginxlocation匹配模式与规则,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录一、环境二、匹配模式1. 精准模式2. 前缀模式(不继续匹配正则)3. 前缀模式(继续匹配正则)4. 正则模式(大

Java 正则表达式URL 匹配与源码全解析

《Java正则表达式URL匹配与源码全解析》在Web应用开发中,我们经常需要对URL进行格式验证,今天我们结合Java的Pattern和Matcher类,深入理解正则表达式在实际应用中... 目录1.正则表达式分解:2. 添加域名匹配 (2)3. 添加路径和查询参数匹配 (3) 4. 最终优化版本5.设计思

openCV中KNN算法的实现

《openCV中KNN算法的实现》KNN算法是一种简单且常用的分类算法,本文主要介绍了openCV中KNN算法的实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的... 目录KNN算法流程使用OpenCV实现KNNOpenCV 是一个开源的跨平台计算机视觉库,它提供了各

Python中使用正则表达式精准匹配IP地址的案例

《Python中使用正则表达式精准匹配IP地址的案例》Python的正则表达式(re模块)是完成这个任务的利器,但你知道怎么写才能准确匹配各种合法的IP地址吗,今天我们就来详细探讨这个问题,感兴趣的朋... 目录为什么需要IP正则表达式?IP地址的基本结构基础正则表达式写法精确匹配0-255的数字验证IP地

浅谈配置MMCV环境,解决报错,版本不匹配问题

《浅谈配置MMCV环境,解决报错,版本不匹配问题》:本文主要介绍浅谈配置MMCV环境,解决报错,版本不匹配问题,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录配置MMCV环境,解决报错,版本不匹配错误示例正确示例总结配置MMCV环境,解决报错,版本不匹配在col

springboot+dubbo实现时间轮算法

《springboot+dubbo实现时间轮算法》时间轮是一种高效利用线程资源进行批量化调度的算法,本文主要介绍了springboot+dubbo实现时间轮算法,文中通过示例代码介绍的非常详细,对大家... 目录前言一、参数说明二、具体实现1、HashedwheelTimer2、createWheel3、n

详解nginx 中location和 proxy_pass的匹配规则

《详解nginx中location和proxy_pass的匹配规则》location是Nginx中用来匹配客户端请求URI的指令,决定如何处理特定路径的请求,它定义了请求的路由规则,后续的配置(如... 目录location 的作用语法示例:location /www.chinasem.cntestproxy