使用匈牙利算法来解决二分图的最大匹配问题

其实在写这个的代码的时候我是纳闷的,X集合和Y集合的点,能同时用1,或者2来表示吗?

然后我努力说服自己:它已经是二分图了

它就是存了一个 → 而已

好的我被自己说服了

二分图匹配说的就是,每个人有若干种选择,但是每种选择只能容纳一个人,问你最多能配对多少

或者说成选边的时候不能经过同一个点

最大匹配就是最多选择多少条边的问题

匈牙利算法就是,有机会就上,没机会要创造机会也要上,尽可能地给当前腾地方,腾的过程是一个递归的过程

其实这个算法挺矫情的。。

bool find(int u)
{
    for(int tmp=g[u];tmp;tmp=e[tmp].next)
        if(!y[e[tmp].t])
        {
            y[e[tmp].t]=1;
            if(lk[e[tmp].t]==0||find(lk[e[tmp].t]))
            {
                lk[e[tmp].t]=u;
                return 1;
            }
        }
        return 0;
}

建图之后,对于每个X中的点,清空y数组之后find就好了

然后忘了说定义了,补上。。

int n,m,cnt,ans;
int y[maxn],lk[maxn],g[maxn];

y记录的是Y中的下标节点是否被访问过

lk记录的是与当前下标节点(Y中)相连的X中的节点

然后给出完整实现:

 1 #include<cstdio>
 2 #include<cstring>
 3 const int maxn=205;
 4 const int maxm=205;
 5 int n,m,cnt,ans;
 6 int y[maxn],lk[maxn],g[maxn];
 7 struct Edge{int t,next;}e[maxn*maxm];
 8 void addedge(int u,int v)
 9 {
10     e[++cnt].t=v;e[cnt].next=g[u];
11     g[u]=cnt;
12 }
13 bool find(int u)
14 {
15     for(int tmp=g[u];tmp;tmp=e[tmp].next)
16         if(!y[e[tmp].t])
17         {
18             y[e[tmp].t]=1;
19             if(lk[e[tmp].t]==0||find(lk[e[tmp].t]))
20             {
21                 lk[e[tmp].t]=u;
22                 return 1;
23             }
24         }
25         return 0;
26 }
27 int main()
28 {
29     scanf("%d%d",&n,&m);
30     int tmp,tmp1;
31     for(int i=1;i<=n;i++)
32     {
33         scanf("%d",&tmp);
34         for(int j=1;j<=tmp;j++)
35         {
36             scanf("%d",&tmp1);
37             addedge(i,tmp1);
38         }
39     }
40     for(int i=1;i<=n;i++)
41     {
42         memset(y,0,sizeof(y));
43         if(find(i)) ans++;
44     }
45     printf("%d",ans);
46     return 0;
47 }

老实说,这个算法,真的很神奇。。

猜你喜欢

转载自www.cnblogs.com/aininot260/p/9434172.html