匈牙利算法是一种用于计算最大匹配的算法
......
什么是匹配呢,简单来说就是两点一线。例如一个选手匹配一台计算机。这两个点分别来自两个不同集合
假如现在给你N个选手,M台机子,每个选手有他讨厌的机子,问最多能满足多少个选手的喜好,这就是一个典型的最大匹配问题
最大匹配问题可以用网络流解决,用一个超级源点接上一个集合的所有点,边上容量为1;
一个超级汇点接上另一个集合的所有点,边的容量也为1。跑一遍最大流就好啦。
但是我们发现这个网络流有特殊型:边的容量都为1;有没有更简便的算法呢,匈牙利算法便诞生啦。
首先一个点要找到匹配它的点,必须满足 1 它们有边连接 2 这个点没有被匹配,或是在不减少匹配数的前提下能把它空出来 。
那么重要的就是把这个点空出来了。下面结合代码解释。
int link[17005],vis[17005];//link[i]表示i的匹配对象,vis[i]表示i是否访问过。
int find(int x)//询问x是否能找到匹配对象
{
for(int k=head[x];k;k=nxt[k])//遍历x的边
{
int v=des[k];//v为我们的候选对象
if(!vis[v])//v必须没有被我们访问过
{
vis[v]=1;
if(link[v]==0||find(link[v]))//v没有被匹配或是v现在匹配的对象能找到新对象
{
link[v]=x;//v与x匹配。
return 1;//匹配成功。
}
}
}
return 0;//否则匹配失败
}//注意每次进入函数前需清零vis[]数组
用匈牙利算法其实最重要的是搞清楚那两个集合与边的意义。
一般符合的题意性质有:
(1) 选了这个,就不能选与之相连的那个
(2) 任选了一条路径的两个端点之一都算是选了这条边
这里再贴一道题:有N个障碍分布在一个K*M的矩阵里,给出每个障碍的坐标。一次可以消除一行或一列的障碍。问最小消除多少次能消掉所有障碍(N,K,M<=10000)。
其实最大匹配有各种应用,这里再贴道题吧。poj3020天线放置。(比较难了)