您的位置:首页 > 其它

二分图匹配之 匈牙利算法简单学习后感

2017-02-18 18:33 316 查看
匈牙利算法的核心就是 增广路定理,能够理解增广路定理其实就理论理解了 匈牙利算法。

讲匈牙利算法的文章很多了,就不在这里关公面前耍大刀了。

个人对匈牙利算法的理解:

  先将图分为左边的点,和右边的点以后。

  对左边的每一个没有匹配的点,进行搜索是否有增广路,如果搜寻到了, 就可以   使当前这个左边的点成为匹配点的同时,使匹配边数+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]; //交替路标记
vector<int>edge[inf];

int dfs(int u)
{
int len=edge[u].size();
for(int i=0;i<len;i++)
{
int v=edge[u][i];
if(!book[v])
{
book[v]=1;
if(ans[v]==-1||dfs(ans[v]))
{
ans[v]=u;
ans[u]=v;
return 1;
}
}
}
return 0;
}

int XYL()
{
int i,j;
for(i=0;i<n;i++)
{
if(ans[i]==-1)
{
memset(book,0,sizeof book);
res+=dfs(i);
}
}
return res;
}

void init()
{
for(int i=0;i<n;i++){edge[i].clear();ans[i]=-1;}
res=0;
}
int main()
{
int i,j;
scanf("%d%d",&n,&m);
init();

while(m--)
{
int x,y;
scanf("%d%d",&x,&y);
edge[x].push_back(y);
edge[y].push_back(x);
}

printf("%d\n",XYL());
return 0;
}


  还有一种情况应该更大众吧,就是
左边的点和右边的点 分开编号给出,都从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;x<z;x++)
int p,n,sum;
int ans[309],book[309];
vector<int>edge[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;
re
c4c9
turn 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;
}
[/code]

 
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: