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 ...
随机推荐
- css sprite的实现
css sprite 为什么使用css sprite? 网页上的非常多静态小图片在载入时须要大量http请求,添加了响应时间.(哈哈.雅虎34条优化法则的第一条啊) css的background-po ...
- Rose2003执行出现 -2147417848 (80010108)':Automation 错误
上篇博客在结尾的时候.我提到了Ration Rose2003执行出现"-2147417848 (80010108)':Automation错误"的问题.今天这篇博客就来介绍一下怎样 ...
- COGS 2580. [HZOI 2015]偏序 II
COGS 2580. [HZOI 2015]偏序 II 题目传送门 题目大意:给n个元素,每个元素有具有4个属性a,b,c,d,求i<j并且ai<aj,bi<bj,ci<cj, ...
- Swift - 使用CollectionView实现图片Gallery画廊效果(左右滑动浏览图片)
1,效果图 (1)图片从左至右横向排列(只有一行),通过手指拖动可以前后浏览图片. (2)视图滚动时,每张图片根据其与屏幕中心距离的不同,显示尺寸也会相应地变化.越靠近屏幕中心尺寸就越大,远离屏幕中心 ...
- [POI 2007] 旅游景点
[题目链接] https://www.lydsy.com/JudgeOnline/problem.php?id=1097 [算法] 首先,用Dijkstra算法求出2-k+1到每个点的最短路 然后,我 ...
- Tomcat配置自签名https
从JDK中找到keytool.exe,随便复制到一个方便的目录,在命令行中进入这个目录. 第一步:为服务器生成证书 tomcat.keystore,命令中如果是IP方式访问用-ext SAN=ip:1 ...
- Sqlite基本命令集合(linux/fedora/ubuntu)
注:fedora自带sqlite3,无需安装,直接输入命令sqlite3即可. ------------Ubuntu在命令行输入sqlite3,确认没有安装在进行--- 1.安装sqlite3 ubu ...
- Android的Activity的小知识点
1.android的四种启动模式分别是:standard,singleTop,SingleTask,singleInstance. 我们可以在AndroidMainfest.xml中通过Activit ...
- Unity的SendMessage方法
用法(该对象所有脚本都能收到): gameObject.SendMessage("要执行的方法名"); 通知的另一种实现: gameObject.GetComponent<脚 ...
- ZBrush软件特性之Layers
ZBrush®中的Layers层调控板可以在单个文档工作中添加多个层,实际上是把新建的层作为一个分离的文档,层之间可以相互影响. 使用层工作 Layers调控板为每个层都有预置存放的空间,刚启动ZBr ...