0
点赞
收藏
分享

微信扫一扫

二分匹配


原理介绍:

​​http://www.renfei.org/blog/bipartite-matching.html​​(这篇好:二分图的最大匹配、完美匹配和匈牙利算法)

二分图最大匹配的模板

//二分图最大匹配模板,二分图都是无向图
//调用下面算法前,保证本图是二分图
/*************vecotr模板*****************/
#include<cstdio>
#include<iostream>
#include<fstream>
#include<algorithm>
#include<functional>
#include<cstring>
#include<string>
#include<cstdlib>
#include<iomanip>
#include<numeric>
#include<cctype>
#include<cmath>
#include<ctime>
#include<queue>
#include<stack>
#include<list>
#include<set>
#include<map>
using namespace std;
const int maxn = 100 + 5;

struct Max_Match
{
int n, m;//左右点集大小,点从1开始编号
vector<int> g[maxn];//g[i]表示左边第i个点邻接的右边点的集合
bool vis[maxn];//vis[i]表示右边第i个点是否在本次match中被访问过
int left[maxn];//left[i]==j表右边第i个点与左边第j个点匹配,为-1表无点匹配

void init(int n, int m)
{
this->n = n;
this->m = m;
for (int i = 1; i <= n; i++) g[i].clear();///点从1开始编号
memset(left, -1, sizeof(left));
}

//判断从左u点是否可以找到一条增广路
bool match(int u)
{
for (int i = 0; i<g[u].size(); i++)
{
int v = g[u][i];
if (!vis[v])
{
vis[v] = true;
if (left[v] == -1 || match(left[v]))//找到增广路
{
left[v] = u;
return true;
}
}
}
return false;
}

//返回当前二分图的最大匹配数
int solve()
{
int ans = 0;//最大匹配数
for (int i = 1; i <= n; i++)//每个左边的节点找一次增广路
{
memset(vis, 0, sizeof(vis));
if (match(i)) ans++;//找到一条增广路,形成一个新匹配
}
return ans;
}
}MM;
/*************vecotr模板*****************/
int main()
{
int n, m;
while (scanf("%d%d", &n, &m) != -1)
{
MM.init(n,m);
for (int i = 1; i <= m; i++)
{
int num;
scanf("%d", &num);
while (num--)
{
int a;
scanf("%d", &a);
MM.g[i].push_back(a);
}
}
printf("%d\n", MM.solve());
}
}

二分图最优完美匹配模板

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn=100+5;

//把W[maxn][maxn]数组的内容读进去之后,调用solve(n)即可计算出二分图最优匹配
//不过需要保证该图肯定有完美匹配
//因为本图用的W[][]来表示一个完全图,所以一定存在完美匹配的
struct Max_Match
{
int W[maxn][maxn],n; //W是权值矩阵,n为左右点集大小
int Lx[maxn],Ly[maxn];//左右点集的可行顶标值
bool S[maxn],T[maxn]; //标记左右点集是否已被访问过
int left[maxn]; //left[i]=j表右i与左j匹配,为-1时表无匹配

bool match(int i)
{
S[i]=true;
for(int j=1;j<=n;j++)if(Lx[i]+Ly[j]==W[i][j] && !T[j])
{
T[j]=true;
if(left[j]==-1 || match(left[j]))
{
left[j]=i;
return true;
}
}
return false;
}

//更新可行顶标,纳入更多的边进来
void update()
{
int a=1<<30;
for(int i=1;i<=n;i++)if(S[i])
for(int j=1;j<=n;j++)if(!T[j])
{
a = min(a,Lx[i]+Ly[j]-W[i][j]);
}
for(int i=1;i<=n;i++)
{
if(S[i]) Lx[i]-=a;
if(T[i]) Ly[i]+=a;
}
}

int solve(int n)
{
this->n=n;
memset(left,-1,sizeof(left));
for(int i=1;i<=n;i++)//初始化可行顶标值
{
Lx[i]=Ly[i]=0;
for(int j=1;j<=n;j++)
Lx[i]=max(Lx[i], W[i][j]);
}

for(int i=1;i<=n;i++)
{
while(true)
{
for(int j=1;j<=n;j++) S[j]=T[j]=false;
if(match(i)) break;
else update();
}
}

int ans=0;//最优完美匹配的权值
for(int i=1;i<=n;i++) ans+= W[left[i]][i];
return ans;
}
}KM;

例题:

  • ​​hdu1179Ollivanders: Makers of Fine Wands since 382 BC.  ​​   (二分最大匹配) 
  • ​​POJ 1466 Girls and Boys               ​​                                         (二分图最大独立集)
  • ​​POJ 1325 Machine Schedule      ​​                                               (二分图最小点覆盖)
  • ​​HDU 2119 Matrix              ​​                                                     (二分图最小点覆盖)
  • ​​POJ - 1419  Graph Coloring        ​​                                         (最大团+输出路径模板
  • ​​HDU 1498 50 years, 50 colors​​                                                 (二分图最小点覆盖)
举报

相关推荐

0 条评论