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 ...
随机推荐
- Android图文混排-实现EditText图文混合插入上传
前段时间做了一个Android会议管理系统,项目需求涉及到EditText的图文混排,如图: 在上图的"会议详情"中.须要支持文本和图片的混合插入,下图演示输入的演示样例: 当会议 ...
- 【POJ 1733】 Parity Game
[题目链接] http://poj.org/problem?id=1 [算法] 并查集 [代码] #include <algorithm> #include <bitset> ...
- ACM/OI 出题用
之前出题,很苦恼出数据和检查程序,因为很多繁琐的工作,还很可能小手一抖出问题. 最近又在出题...想起之前的对拍脚本,感觉不能更方便,于是撸了一套出题用的小工具,也学习了一点点的DOS命令 首先是输入 ...
- 从git源码安装zabbix-agent
从网上随便找了几个image,都是从svn下载的代码,根本跑不了,于是自己重新做了个,从git上拿的源码,只是build出来的image有点大,有时间再优化了 Dockerfile FROM cent ...
- 11.MATLAB基本编程
概述: 1 脚本M文件 clear all; %设置精度 format long; %定义变量 n= s= %循环 :n s=s+/^i; end s format short; 2 函数M文件 fu ...
- composer的一些操作
版本更新 命令行下:composer self-update 设置中国镜像 composer config -g repo.packagist composer https://packagist.p ...
- poj 3160 Father Christmas flymouse【强连通 DAG spfa 】
和上一道题一样,可以用DAG上的动态规划来做,也可以建立一个源点,用spfa来做 #include<cstdio> #include<cstring> #include< ...
- 手游服务器端接入google的SDK
在接入google的SDK之前,当然先要用你的google开发者账号要去申请你接入的应用,这些步骤就直接省略了具体的步骤可以查看这篇博文:http://blog.csdn.net/hjun01/art ...
- Prime Distance POJ - 2689 线性筛
一个数 $n$ 必有一个不超过 $\sqrt n$ 的质因子. 打表处理出 $1$ 到 $\sqrt n$ 的质因子后去筛掉属于 $L$ 到 $R$ 区间的素数即可. Code: #include&l ...
- jq——html,text,val和对象访问
html代码 1.html():获取的是对象内的html代码,类似于innerHTML 2.html(代码):设置html的内容,替换 $("div").html("hh ...