Maximum Bipartite Matching
算法旨在用尽可能简单的思路解决这个问题。理解算法也应该是一个越看越简单的过程,当你看到算法里的一串概念,或者一大坨代码,第一感觉是复杂,此时最好还是从样例入手。通过一个简单的样例,并编程实现,这个过程事实上就能够理解清楚算法里的最重要的思想,之后扩展。对算法的引理或者更复杂的情况。对算法进行改进。最后,再考虑时间和空间复杂度的问题。
了解这个算法是源于在Network Alignment问题中。图论算法用得比較多。而对于alignment。特别是pairwise alignment, 又常常遇到maximum bipartite matching问题,解决问题,是通过Network Flow问题的解法来实现。
一、Network Flow
Network Flow,指的是在从source 到 destination的路径组成一个network, 每条边有一个capacity, 表示从这条边上能通过的最大信息流,而Network Flow问题则要找出从源到目的地能通过的最大流, Maximum Flow. 信息在流动的过程中须要遵循两个原则;
1. 对于每一个节点,流入和流出的信息必须相等。
2.流过每条边的信息不能超过边上的capacity.
最大流问题和minimum cut是等价的,找最大流也就是找minimum cut,minimum cut是例如以下定义的:
我们要在Network上删除一些边。删除掉这些边后,从source 就没有路径到目的地了,我们要找到尽可能少的边,来达到这个目的,这就是minimum cut。
二、 Ford-Fulkerson算法
第一遍读这个算法的时候。不懂,如今读这个算法,认为非常清晰,如今把算法的思路复述一遍。不知道第一次读的人会不会认为easy理解:
1、 构建Residual graph:由于在原network上已经有了capacity, 如今给定这个网络一个流flow的值, 比如边是(u,v)我们计算capacity-f, 同一时候我们也计算(v,u),值为f(由于capacity为0),
假设一条边的这个值为正,则保留,否则删除。
2、augmenting path: 通过1得到的就是Residual graph,这个graph上的从source到destination的全部路径都叫做augmenting path.
3、针对每条augmenting path: 改变path上全部边的capacity,改变规则例如以下(以(u,v)为例):
找到这条path上的最小的capacity, f,
降低u->v的capacity, 添加v->u的capacity.
算法的时间复杂度 O(m+n)f),f是max-flow.
代码:
// C++ program for implementation of Ford Fulkerson algorithm
#include <iostream>
#include <limits.h>
#include <string.h>
#include <queue> using namespace std; // Number of vertices in given graph
#define V 6 /* Returns true if there is a path from source 's' to sink 't' in
residual graph. Also fills parent[] to store the path */
bool bfs(int rGraph[V][V], int s, int t, int parent[])
{
// Create a visited array and mark all vertices as not visited
bool visited[V];
memset(visited, 0, sizeof(visited)); // Create a queue, enqueue source vertex and mark source vertex
// as visited
queue <int> q;
q.push(s);
visited[s] = true;
parent[s] = -1; // Standard BFS Loop
while (!q.empty())
{
int u = q.front();
q.pop(); for (int v=0; v<V; v++)
{
if (visited[v]==false && rGraph[u][v] > 0)
{
q.push(v);
parent[v] = u;
visited[v] = true;
}
}
} // If we reached sink in BFS starting from source, then return
// true, else false
return (visited[t] == true);
} // Returns tne maximum flow from s to t in the given graph
int fordFulkerson(int graph[V][V], int s, int t)
{
int u, v; // Create a residual graph and fill the residual graph with
// given capacities in the original graph as residual capacities
// in residual graph
int rGraph[V][V]; // Residual graph where rGraph[i][j] indicates
// residual capacity of edge from i to j (if there
// is an edge. If rGraph[i][j] is 0, then there is not)
for (u = 0; u < V; u++)
for (v = 0; v < V; v++)
rGraph[u][v] = graph[u][v]; int parent[V]; // This array is filled by BFS and to store path int max_flow = 0; // There is no flow initially // Augment the flow while tere is path from source to sink
while (bfs(rGraph, s, t, parent))
{
// Find minimum residual capacity of the edhes along the
// path filled by BFS. Or we can say find the maximum flow
// through the path found.
int path_flow = INT_MAX;
for (v=t; v!=s; v=parent[v])
{
u = parent[v];
path_flow = min(path_flow, rGraph[u][v]);
} // update residual capacities of the edges and reverse edges
// along the path
for (v=t; v != s; v=parent[v])
{
u = parent[v];
rGraph[u][v] -= path_flow;
rGraph[v][u] += path_flow;
} // Add path flow to overall flow
max_flow += path_flow;
} // Return the overall flow
return max_flow;
} // Driver program to test above functions
int main()
{
// Let us create a graph shown in the above example
int graph[V][V] = { {0, 16, 13, 0, 0, 0},
{0, 0, 10, 12, 0, 0},
{0, 4, 0, 0, 14, 0},
{0, 0, 9, 0, 0, 20},
{0, 0, 0, 7, 0, 4},
{0, 0, 0, 0, 0, 0}
}; cout << "The maximum possible flow is " << fordFulkerson(graph, 0, 5); return 0;
}
三、Maximum Bipartite Matching
解决问题就非常easy了。我们先加入上源和目的地节点。如果是任务分配问题,则源能够有边指向全部人。全部任务有边能够指向目的地,我们要找的是人和任务之间的最优匹配。
代码:
// A C++ program to find maximal Bipartite matching.
#include <iostream>
#include <string.h>
using namespace std; // M is number of applicants and N is number of jobs
#define M 6
#define N 6 // A DFS based recursive function that returns true if a
// matching for vertex u is possible
bool bpm(bool bpGraph[M][N], int u, bool seen[], int matchR[])
{
// Try every job one by one
for (int v = 0; v < N; v++)
{
// If applicant u is interested in job v and v is
// not visited
if (bpGraph[u][v] && !seen[v])
{
seen[v] = true; // Mark v as visited // If job 'v' is not assigned to an applicant OR
// previously assigned applicant for job v (which is matchR[v])
// has an alternate job available.
// Since v is marked as visited in the above line, matchR[v]
// in the following recursive call will not get job 'v' again
if (matchR[v] < 0 || bpm(bpGraph, matchR[v], seen, matchR))
{
matchR[v] = u;
return true;
}
}
}
return false;
} // Returns maximum number of matching from M to N
int maxBPM(bool bpGraph[M][N])
{
// An array to keep track of the applicants assigned to
// jobs. The value of matchR[i] is the applicant number
// assigned to job i, the value -1 indicates nobody is
// assigned.
int matchR[N]; // Initially all jobs are available
memset(matchR, -1, sizeof(matchR)); int result = 0; // Count of jobs assigned to applicants
for (int u = 0; u < M; u++)
{
// Mark all jobs as not seen for next applicant.
bool seen[N];
memset(seen, 0, sizeof(seen)); // Find if the applicant 'u' can get a job
if (bpm(bpGraph, u, seen, matchR))
result++;
}
return result;
} // Driver program to test above functions
int main()
{
// Let us create a bpGraph shown in the above example
bool bpGraph[M][N] = { {0, 1, 1, 0, 0, 0},
{1, 0, 0, 1, 0, 0},
{0, 0, 1, 0, 0, 0},
{0, 0, 1, 1, 0, 0},
{0, 0, 0, 0, 0, 0},
{0, 0, 0, 0, 0, 1}
}; cout << "Maximum number of applicants that can get job is "
<< maxBPM(bpGraph); return 0;
}
四、对于任务分配问题,还有Hungrian算法,这个后面再讲。此算法的时间复杂度和空间复杂度以及改进也能够探讨
Maximum Bipartite Matching的更多相关文章
- Maximum Cardinality Bipartite Matching: Augmenting Path Algorithm
http://www.csie.ntnu.edu.tw/~u91029/Matching.html int nx,ny; int mx[N],my[N]; bool vy[N]; bool g[N][ ...
- Maximum Flow and Minimum Cut
最大流最小割 Introduction Mincut Problem 最小割问题,输入是带权有向图,有一个源点 s(source)和一个汇点 t(target),边的权重在这里称作容量(capacit ...
- Hdu 1052 Tian Ji -- The Horse Racing
Tian Ji -- The Horse Racing Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (J ...
- nyoj 364 田忌赛马(贪心)
田忌赛马 时间限制:3000 ms | 内存限制:65535 KB 难度:3 描述 Here is a famous story in Chinese history. "That ...
- ACM 田忌赛马
田忌赛马 时间限制:3000 ms | 内存限制:65535 KB 难度:3 描述 Here is a famous story in Chinese history. "That ...
- SPOJ 375. Query on a tree (树链剖分)
Query on a tree Time Limit: 5000ms Memory Limit: 262144KB This problem will be judged on SPOJ. Ori ...
- HDU 1052 Tian Ji -- The Horse Racing(贪心)(2004 Asia Regional Shanghai)
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1052 Problem Description Here is a famous story in Ch ...
- HDUOJ-------1052Tian Ji -- The Horse Racing(田忌赛马)
Tian Ji -- The Horse Racing Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (J ...
- 【策略】UVa 1344 - Tian Ji -- The Horse Racing(田忌赛马)
Here is a famous story in Chinese history. That was about 2300 years ago. General Tian Ji was a high ...
随机推荐
- CDH使用秘籍(一):Cloudera Manager和Managed Service的数据库
背景 从业务发展需求,大数据平台须要使用spark作为机器学习.数据挖掘.实时计算等工作,所以决定使用Cloudera Manager5.2.0版本号和CDH5. 曾经搭建过Cloudera Mana ...
- angularjs1-1
<!DOCTYPE html> <html> <body> <header> <meta http-equiv="Content-Typ ...
- PHPStorm中使用bootstrap3控件!
PHPStorm中使用bootstrap3控件! 奇怪为什么不自动提示呢? 原来需要Ctrl+j才显示出来! 很方便的控件!!!!
- poj--1236--Network of Schools(scc+缩点)
Network of Schools Time Limit: 1000MS Memory Limit: 10000K Total Submissions: 14062 Accepted: 56 ...
- 谷歌浏览器 —— 快捷键(vimium:像使用 vim 一样操作当前页面)
Chrome 键盘快捷键 拷贝当前页面内的某链接: 首先输入 y(进入 yank 模式),输入 f,为当前页面内的全部超链接编号,然后输入待拷贝的链接编号,即可将该链接复制到粘贴板: 1. 使用 vi ...
- oracle init.ora常用配置详解
参考网上整理了重要的配置文件 db_name = "51cto" 一个数据库标识符,应与CREATE DATABASE 语句中指定的名称相对应. instance_name = ...
- float类型和double类型的二进制存储
在32位环境下, float占用32位,double占用64位, 目前C/C++编译器标准都遵照IEEE制定的浮点数表示法来进行float,double运算.这种结构是一种科学计数法,用符号.指数和 ...
- htmlunit 简单操作
首先我们新建一个Maven普通客户端项目,然后打开pom.xml 引入htmlunit支持: <dependency> <groupId>net.sourceforge.htm ...
- Api接口服务的设计和安全解决方案
这个涉及到两个方面问题:一个是接口访问认证问题,主要解决谁可以使用接口(用户登录验证.来路验证)一个是数据数据传输安全,主要解决接口数据被监听(HTTPS安全传输.敏感内容加密.数字签名) 普通网站应 ...
- POJ 2923 DP
题意: 两辆车去运一堆货物,货物数量小于等于10,问最少需要几趟能把货物全部运到目的地. 思路: 思路很简单,就是状态压缩成二进制.判断一下每个状态能不能运输.再进行一下DP. 设s[]数组里记录所有 ...