算法旨在用尽可能简单的思路解决这个问题。理解算法也应该是一个越看越简单的过程,当你看到算法里的一串概念,或者一大坨代码,第一感觉是复杂,此时最好还是从样例入手。通过一个简单的样例,并编程实现,这个过程事实上就能够理解清楚算法里的最重要的思想,之后扩展。对算法的引理或者更复杂的情况。对算法进行改进。最后,再考虑时间和空间复杂度的问题。

了解这个算法是源于在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的更多相关文章

  1. 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][ ...

  2. Maximum Flow and Minimum Cut

    最大流最小割 Introduction Mincut Problem 最小割问题,输入是带权有向图,有一个源点 s(source)和一个汇点 t(target),边的权重在这里称作容量(capacit ...

  3. 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 ...

  4. nyoj 364 田忌赛马(贪心)

    田忌赛马 时间限制:3000 ms  |  内存限制:65535 KB 难度:3   描述 Here is a famous story in Chinese history. "That ...

  5. ACM 田忌赛马

    田忌赛马 时间限制:3000 ms  |  内存限制:65535 KB 难度:3   描述 Here is a famous story in Chinese history. "That ...

  6. SPOJ 375. Query on a tree (树链剖分)

    Query on a tree Time Limit: 5000ms Memory Limit: 262144KB   This problem will be judged on SPOJ. Ori ...

  7. 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 ...

  8. HDUOJ-------1052Tian Ji -- The Horse Racing(田忌赛马)

    Tian Ji -- The Horse Racing Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (J ...

  9. 【策略】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 ...

随机推荐

  1. itunes connect上传截图提示无法加载文件问题

    解决的方法: 图片名字中不能包括汉字,要英文字母或数字.

  2. 调用imagemagick做响应图片

    设计出图后经常需要改下尺寸放在别的项目上使用,每次都是设计手工处理,其实图片服务可以做更多事情,比如借助强大的im,可以通过url控制图片尺寸 var childProcess = require(' ...

  3. PHP生成二维码的2种方式

    二维码的用处俺也就不说了,看一下用PHP生成的二维码吧. 利用谷歌提供的API 生成二维码,如今非常多国外站点都提供了这类API 看下代码吧<=======================> ...

  4. oracle经常使用函数(2)

    1.TRIM([ { { LEADING | TRAILING | BOTH }[ trim_character ]| trim_character} FROM ]trim_source) 函数 參数 ...

  5. nyoj--1185--最大最小值(线段树)

    最大最小值 时间限制:1000 ms  |  内存限制:65535 KB 难度:2 描述 给出N个整数,执行M次询问. 对于每次询问,首先输入三个整数C.L.R: 如果C等于1,输出第L个数到第R个数 ...

  6. Jmeter执行多条Mysql语句报错

    花了很长时间找原因,Jmeter一直返回的是MySql语法错误,就写了两条很简单的删除语句,并且在MySql里可以正常执行 包括换了jdbc驱动包,更改不同的Query Type等 后来发现两条语句拆 ...

  7. SQL语句之Group By

    1. Group By 语句简介: Group By语句从英文的字面意义上理解就是“根据(by)一定的规则进行分组(Group)”.它的作用是通过一定的规则将一个数据集划分成若干个小的区域,然后针对若 ...

  8. Tomcat 初探(一) 简介

    简述 大部分入了 Java 开发这个坑的朋友,都需要把自己的网站发布到 Web 服务器上,相信也听过 Tomcat 的鼎鼎大名.Tomcat 是由 Sun 公司软件架构师詹姆斯·邓肯·戴维森开发的 W ...

  9. USACO Sabotage, 2014 Mar 破坏阴谋(二分+贪心)

    一开始看完这题就有个想法: 只要把大于整个序列平均数的最大连续序列就是最优? 那把整个序列都减掉平均数 在做最大连续字序列和且记录长度? 仔细思考一下并不太对: 当子序列最大但长度较大 也许也比不上删 ...

  10. MyBatis数据持久化(十)与Spring4整合

    前面几节介绍了mybatis的基本使用方法,本节主要介绍如何使用mybatis与主流的IoC容器Spring进行整合. 我们首先需要获取Spring框架的jar文件,在写本文时spring的最新Rel ...