匈牙利算法是由匈牙利数学家Edmonds于1965年提出,因而得名。匈牙利算法是基于Hall定理中充分性证明的思想,它是部图匹配最常见的算法,该算法的核心就是寻找增广路径,它是一种用增广路径求二分图最大匹配的算法。
时间复杂度邻接矩阵:最坏为O(n^3)邻接表:O(mn)
空间复杂度 邻接矩阵:O(n^2) 邻接表:O(m+n)
例子:
一: 先试着给1号男生找妹子,发现第一个和他相连的1号女生还名花无主,got it,连上一条蓝线
二:接着给2号男生找妹子,发现第一个和他相连的2号女生名花无主,got it
三:接下来是3号男生,很遗憾1号女生已经有主了,怎么办呢?
我们试着给之前1号女生匹配的男生(也就是1号男生)另外分配一个妹子。
(黄色表示这条边被临时拆掉)
重新找个妹子(注意这个步骤和上面是一样的,这是一个递归的过程)
此时发现2号男生还能找到3号女生,那么之前的问题迎刃而解了,回溯回去。
2号男生可以找3号妹子~~~ 1号男生可以找2号妹子了~~~ 3号男生可以找1号妹子
所以第三步最后的结果就是:
四: 接下来是4号男生,很遗憾,按照第三步的节奏我们没法给4号男生腾出来一个妹子,我们实在是无能为力了……香吉士同学走好。
这就是匈牙利算法的流程,其中找妹子是个递归的过程,最最关键的字就是“腾”字===============================================================================
theme:n只羊在一条长度为400的线段上,每只羊只会在它喜欢的区间[a,b]吃草,只会位于整数点处,且每时刻每个点只会有一只羊,先q次询问,每次询问区间[l,r]中最多有多少只羊吃草。1<=n,q<=400
solution:二分匹配。将羊与它喜欢的区间相连,则进行q次匹配,在匈牙利算法dfs为给定节点u配对是判断一下v是否位于[l,r]范围即可。
//匹配指定右区间
#include
using namespace std;
#define re(i,n) for(int i=0;iG[N];
int n,m,q;
int l,r;
void createG()
{
for(int i=1;i<=n;i++)
scanf("%d",&a[i]);
for(int i=1;i<=n;i++)
scanf("%d",&b[i]);
for(int i=1;i<=n;i++)
{
for(int j=a[i];j<=b[i];++j)
G[i].push_back(j);
}
}
bool dfs(int u)
{
for (int i=0;i=l&&v<=r && used[v]==false)
{
used[v]=1;
if (linker[v]==0 || dfs(linker[v])) {////名花无主或者能腾出个位置来,这里使用递归
linker[v]=u;
return true;
}
}
}
return false;
}
//匈牙利算法求二分图最大匹配
int hungary()
{
int ans=0;
fill(linker,linker+m+5,0);
for(int u=1; u<=n; ++u)//给每个左节点找右节点
{
fill(used,used+m+5,0);
if(dfs(u))//如果能成功给节点u找到一个匹配的右节点,且不影响之前选过的节点,则结果+1
ans++;
}
return ans;
}
int main()
{
cin>>n>>q;
m=401;
createG();
for(int i=1;i<=q;i++)
{
scanf("%d%d",&l,&r);
int ans=hungary();
printf("%d\n",ans);
}
}
theme:n只牛m个坑,每只牛一个坑,每个坑只能占一只牛,给出每只牛能取哪几个坑,问最多能安排好多少只牛占一个坑。0 <= N,M<= 200
solution:裸的二分图匹配
//theme:n只牛m个坑,每只牛一个坑,每个坑只能占一只牛,给出每只牛能取哪几个坑,问最多能安排好多少只牛占一个坑。0 <= N,M<= 200
#include
#include
#include
using namespace std;
#define re(i,n) for(int i=0;i
theme:n个男生,m个女生,其中女生之间、男生之间相互认识,有些女生与有些男生相互认识,问最能能从中选出多少人来是的任意两人相互认识?1 ≤ G, B ≤ 200
solution:由题意可知是求最大团,最大团为选最大的点集使得任意两点之间都有边,而最大团=补图的最大独立集,最大独立集=总的点数-最大匹配
//theme:n个男生,m个女生,其中女生之间、男生之间相互认识,有些女生与有些男生相互认识,问最能能从中选出多少人来是的任意两人相互认识?1 ≤ G, B ≤ 200
//最大团
#include
#include
#include
using namespace std;
#define re(i,n) for(int i=0;i
theme:n个人,m间房,给出每个人能去哪几间房和房间最大容量,问这n个人能否都入住?1 <= n <= 100000, 1 <= m <= 10.
solution:二分多重匹配.
可以用网络流,加上一个源点与汇点。但节点数太大,可以考虑状态压缩,把n个人按能去的房间数组合,最多有2^10种
//theme:n个人,m间房,给出每个人能去哪几间房和房间最大容量,问这n个人能否都入住?1 <= n <= 100000, 1 <= m <= 10.
//邻接矩阵的匈牙利多重匹配(右节点有容量)
#include
#include
using namespace std;
#define re(i,n) for(int i=0;i
匈牙利算法参考:https://blog.csdn.net/dark_scope/article/details/8880547