匈牙利算法的核心就是 增广路定理,能够理解增广路定理其实就理论理解了 匈牙利算法。
讲匈牙利算法的文章很多了,就不在这里关公面前耍大刀了。
个人对匈牙利算法的理解:
先将图分为左边的点,和右边的点以后。
对左边的每一个没有匹配的点,进行搜索是否有增广路,如果搜寻到了, 就可以 使当前这个左边的点成为匹配点的同时,使匹配边数+1
可能我这么说也没有说清楚,网上有大牛的更好的讲解的文章,帮助会更大一些。我想说的是 匈牙利算法由于题目出现的两个情况,而出现的两个写法。
一种就是简单版本。
题目例子是:
HDU 1068 男孩和女孩:http://acm.hdu.edu.cn/showproblem.php?pid=1068
这种题目的特点就是: 构成二分图的 左边点和右边点,是混在一起编号,然后给你的。
这样一来,左边的点和右边的点不用分清。 对所有点进行 增广路搜索(DFS)就好了。
代码里的两个数组:
book 是 每一次增光路搜索,判断点有没有搜过。
ans 是 在整个过程中, 记录了每个点的匹配点是什么。
PS: 二分图匹配过程中,每个点要么没有匹配点,要么有且只有一个匹配点
这是我的在这种情况的代码,不是本题的代码....
#include"cstdio"
#include"cstring"
#include"vector"
using namespace std;
#define inf 99999
int n,m; //点,边
int res; //匹配数
int ans[inf]; //各点对应妻子,or -1
int book[inf]; //交替路标记
vectoredge[inf];
int dfs(int u)
{
int len=edge[u].size();
for(int i=0;i
还有一种情况应该更大众吧,就是 左边的点和右边的点 分开编号给出,都从0或者1 开始编号。
这样子就不能一股脑的搜索了。有可能做题的人没有意识到,但是用上面的办法去做应该会很乱很扯....
而且我看到了 kuangbin大神的代码,一直没看懂。 后来自己想通了,很幸运发现和kuangbin大神的想法是一样的.....
题目例子是:
POJ 1469:http://poj.org/problem?id=1469 课程匹配问题。
因为题目已经分好了左边的点和右边的点。
所以对每个左边的点进行搜索。
去掉了判断这个点是不是没有匹配点。
因为,每个点起初都是没有匹配的。而当前点,是不可能被前面的点 给变成匹配点的。
这个判断也就显得多余。
这里面的两个数组:
book 表示 在每一次搜索中,右边的点有没有被 搜索过。
ans 表示 在整个过程中 , 右边的点 对应的 匹配点!!
这个情况下的代码:(饿,是此题的代码)
#include"cstdio"
#include"cstring"
#include"vector"
using namespace std;
#define inf 999999999
#define loop(x,y,z) for(x=y;xedge[109];
void init()
{
sum=0;
memset(ans,-1,sizeof ans);
int i;
loop(i,1,p+1)edge[i].clear();
}
int dfs(int v)
{
int i,len;
len=edge[v].size();
loop(i,0,len)
{
int u=edge[v][i];
if(!book[u])
{
book[u]=1;
if(ans[u]==-1||dfs(ans[u]))
{
ans[u]=v;
return 1;
}
}
}
return 0;
}
void XYL()
{
int i;
loop(i,1,p+1)
{
memset(book,0,sizeof book);
sum+=dfs(i);
}
}
int main()
{
int i,j,T,k;
scanf("%d",&T);
while(T--)
{
scanf("%d%d",&p,&n);
init();
loop(i,1,p+1)
{
scanf("%d",&j);
while(j--)
{
scanf("%d",&k);
edge[i].push_back(k);
}
}
XYL();
if(sum==p)
printf("YES\n");
else
printf("NO\n");
}
return 0;
}