网络流之二分图最大匹配

时间:2020-12-03 06:08:33

前言:二分图最大匹配往往用于普通的指派问题中,可转换为最大流问题求解,也可以利用二分图的性质及其边的容量为1的特点,简单的实现二分图的最大匹配算法。

问题模型:有n台计算机和k个任务,每台计算机处理的任务种类不同,问如果给每台计算机分配一个任务,一次最多能处理多少个任务。

分析:该问题可以转化为图论模型来分析。设U为所有计算机顶点的集合,V为所有任务类型的集合,u属于U,v属于V,e=(u,v)表示计算机u能处理任务v,E是所有e的集合。

则G=(U||V, E),且G中满足两两不含公共端点的边的集合的最大值,就是我们所要求的最大任务数即二分图中的最大匹配。如果此问题转为最大流求解,只需增加一个源点s

和汇点t,从源点到所有计算机连一条容量为1的有向边,从所有任务到终点t也连一条容量为1的有向边,再在计算机与所能处理的任务之间连一条容量为1的有向边,时间复杂度同求解最大流的一样。当然,考虑到所有边的容量均为1及二分图的性质,我们还可以简单实现二分图的最大匹配算法,时间复杂度O(VE)。

//二分图最大匹配算法的简单实现

#include <iostream>
#include <vector>
using namespace std;

vector<int> G[1000];
int match[1000];
bool used[1000];

int dfs(int v)
{//通过深搜寻找增广路O(E)
   used[v] = 1;
   for(int i = 0; i < G[v].size(); ++i)
   {
      int u = G[v][i], w = match[u];
      if(w == -1 || (!used[w] && dfs(w)))
      {
         match[u] = v;
         match[v] = u;
         return 1;
      }
   }
   return 0;
}

void solve(int n, int k, int e)
{
   int i, j, ans = 0;
   memset(match, -1, sizeof(match));
   for(i = 0; i < n + k; ++i)
   {
      if(match[i] != -1)
         continue;
      memset(used, 0, sizeof(used));
      if(dfs(i))

       ++ans;
  }
   cout << ans << endl;
}

int main()
{
   int n, k, e;
   cin >> n >> k >> e;
   for(int i = 0; i < e; ++i;)
   {
      int u, v;
      cin >> u >> v;
      G[u - 1].push_back(n + v - 1);
      G[n + v - 1].push_back(u - 1);
   }
   solve(n, k, e);
   return 0;
}