二分匹配

PS:二分图匹配这一章的内容,我认为最重要的是要弄清楚概念。

一些定义:

二分图:二分图又称作二部图,是图论中的一种特殊模型。 设G=(V,E)是一个无向图,如

果顶点V可分割为两个互不相交的子集(A,B),并且图中的每条边(ij)所关联

的两个顶点ij分别属于这两个不同的顶点集(i in A,j in B),则称图G为一个

二分图。记为G=(A,B;E)

二分图匹配:给定一个二分图GMG边集的一个子集,如果M满足当中的任意两条边都不依附于同一个顶点,则称M是一个匹配。

需要强调的是:集合A或者B中,本集合中的元素之间是没有关系的

 最大匹配可用最大流来解,最佳匹配可用最大流最小费用流来解。

二分匹配的意义何在,最大匹配、最佳匹配算法的时间复杂度低。

 

一、最大匹配

最大匹配是找到匹配数最多的匹配。

DFS版匈牙利算法: 代码最简洁。时间复杂度为O(n*m), 空间复杂度为O(n*n)

不卡时间大家都喜欢用这个。

BFS版匈牙利算法: 代码稍多。时间复杂度为O(n*m), 空间复杂度为O(n*n)

Hopcroft-Karp算法:对匈牙利算法进行了优化,时间复杂度O(m√n)。代码很长,空间复杂度为O(m*m)

需要说明的是:准备模版的时候还是多准备一些比较好,有些题目是卡时间,有些却是卡空间。所以有些题目用好的算法就是AC不了。

DFS匈牙利算法模版:

 1 //适合边比较多的图
 2 const int N=300;
 3 bool bmap[N][N],bmask[N];
 4 int cx[N],cy[N];
 5 int nx,ny,ans;
 6 int findpath(int u)
 7 {
 8     int i,j;
 9     for(i=1;i<=ny;i++)
10     {
11         if(bmap[u][i]&&!bmask[i])
12         {
13             bmask[i]=1;
14             if(cy[i]==-1||findpath(cy[i]))
15             {
16                 cy[i]=u; cx[u]=i;
17                 return 1;
18             }
19         }
20     }
21     return 0;
22 }
23 void maxmatch()
24 {
25     int i ,j;
26     ans=0;
27     for(i=1;i<=nx;i++) cx[i]=-1;
28     for(i=1;i<=ny;i++) cy[i]=-1;
29     for(i=1;i<=nx;i++)
30     {
31         if(cx[i]==-1)
32         {
33             for(j=1;j<=ny;j++)
34                 bmask[j]=0;
35             ans+=findpath(i);
36         }
37     }
38 }
39 void init()
40 {
41     memset(bmap,0,sizeof(bmap));
42 }
43 
44 (2)匈牙利算法BFS    时间复杂度O(n*m)
45 
46 const int N=1010;
47 int bmap[N][N],cx[N],cy[N],bmask[N],que[N],pre[N];
48 int nx,ny,ans;
49 void maxmatch()
50 {
51     ans=0;
52     int qs,qe;
53     memset(cx,-1,sizeof(cx));
54     memset(cy,-1,sizeof(cy));
55     memset(bmask,-1,sizeof(bmask));
56     for(int i=1;i<=nx;i++)
57     {
58         if(cx[i] == -1)
59         {
60             qs=qe=0;
61             que[qe++]=i;
62             pre[i]=-1;
63             bool flag=0;
64             while(qs<qe&&!flag)
65             {
66                 int u=que[qs];
67                 for(int v=1;v<=ny&&!flag;v++)
68                 {
69                     if(bmap[u][v]&&bmask[v]!=i)
70                     {
71                         bmask[v]=i;que[qe++]=cy[v];
72                         if(cy[v]>=0) pre[cy[v]]=u;
73                         else
74                         {
75                             flag=1;
76                             int d=u,e=v;
77                             while(d!=-1)
78                             {
79                                 int t=cx[d];
80                                 cx[d]=e; cy[e]=d;
81                                 d=pre[d]; e=t;
82                             }
83                         }
84                     }
85                 }
86                 qs++;
87             }
88             if(cx[i]!=-1) ans++;
89         }
90     }
91 }
92 void init()
93 {
94     memset(bmap,0,sizeof(bmap));
95 }
View Code

Hopcroft-Karp算法模版:有时候顶点较多,所以直接用邻接表,没用邻接矩阵。

 1 const int N=10150,INF=0x3f3f3f3f;
 2 int cx[N],cy[N],dx[N],dy[N];
 3 bool bmask[N];
 4 int nx,ny,dis,ans;
 5 vector<int> bmap[N];
 6 bool searchpath()
 7 {
 8     queue<int> q;
 9     dis=INF;
10     memset(dx,-1,sizeof(dx));
11     memset(dy,-1,sizeof(dy));
12     for(int i=1;i<=nx;i++)
13     {
14         if(cx[i]==-1){ q.push(i); dx[i]=0; }
15         while(!q.empty())
16         {
17             int u=q.front(); q.pop();
18             if(dx[u]>dis) break;
19             for(int i=0;i<bmap[u].size();i++)
20             {
21                 int v=bmap[u][i];
22                 if(dy[v]==-1)
23                 {
24                     dy[v]= dx[u] + 1;
25                     if(cy[v]==-1) dis=dy[v];
26                     else
27                     {
28                         dx[cy[v]]= dy[v]+1;
29                         q.push(cy[v]);
30                     }
31                 }
32             }
33         }
34     }
35     return dis!=INF;
36 }
37 int findpath(int u)
38 {
39     for(int i=0;i<bmap[u].size();i++)
40     {
41         int v=bmap[u][i];
42         if(!bmask[v]&&dy[v]==dx[u]+1)
43         {
44             bmask[v]=1;
45             if(cy[v]!=-1&&dy[v]==dis) continue;
46             if(cy[v]==-1||findpath(cy[v]))
47             {
48                 cy[v]=u; cx[u]=v;
49                 return 1;
50             }
51         }
52     }
53     return 0;
54 }
55 void maxmatch()
56 {
57     ans=0;
58     memset(cx,-1,sizeof(cx));
59     memset(cy,-1,sizeof(cy));
60     while(searchpath())
61     {
62         memset(bmask,0,sizeof(bmask));
63         for(int i=1;i<=nx;i++)
64             if(cx[i]==-1) ans+=findpath(i);
65     }
66 }
67 void init()
68 {
69     for(int i=0;i<N;i++) bmap[i].clear();
70 }
View Code

 

题目类型:

1、判断是否构成二分图  http://www.cnblogs.com/Potato-lover/p/3985869.html

2、二分 最大匹配 http://www.cnblogs.com/Potato-lover/p/3989675.html

3、奇偶建图  http://www.cnblogs.com/Potato-lover/p/3991533.html

 

二、最佳匹配

与最大匹配不同的是,最佳匹配是在每一个匹配之间加一个权值。求的就是权值之和最大的匹配。

Kuhn Munkras 算法:时间复杂度为O(m*m*n)

模版:

 1 const int N=110, INF=0x3f3f3f3f;
 2 int Map[N][N],mat1[N],mat2[N];
 3 int KM(int m,int n)
 4 {
 5     int s[N],t[N],a[N],b[N];
 6     int i,j,k,p,q,ans=0;
 7     for(i=0;i<m;i++)
 8     {
 9         a[i]=-INF;
10         for(j=0;j<n;j++)
11             a[i]=Map[i][j]>a[i]?Map[i][j]:a[i];
12         if(a[i]==-INF) return -1;//cannot match
13     }
14     memset(b,0,sizeof(b));
15     memset(mat1,-1,sizeof(mat1));
16     memset(mat2,-1,sizeof(mat2));
17     for(i=0;i<m;i++)
18     {
19         memset(t,-1,sizeof(t));
20         p=q=0;
21         for(s[0]=i;p<=q&&mat1[i]<0;p++)
22         {
23             for(k=s[p],j=0;j<n&&mat1[i]<0;j++)
24             {
25                 if(a[k]+b[j]==Map[k][j]&&t[j]<0)
26                 {
27                     s[++q]=mat2[j]; t[j]=k;
28                     if(s[q]<0)
29                         for(p=j;p>=0;j=p)
30                         {
31                             mat2[j]=k=t[j];p=mat1[k]; mat1[k]=j;
32                         }
33                 }
34             }
35         }
36         if(mat1[i]<0)
37         {
38             i--,p=INF;
39             for(k=0;k<=q;k++)
40             {
41                 for(j=0;j<n;j++)
42                     if(t[j]<0&&a[s[k]]+b[j]-Map[s[k]][j]<p)
43                         p=a[s[k]]+b[j]-Map[s[k]][j];
44             }
45             for(j=0;j<n;j++) b[j]+=t[j]<0?0:p;
46             for(k=0;k<=q;k++) a[s[k]]-=p;
47         }
48 }
49     for(i=0;i<m;i++) ans+=Map[i][mat1[i]];
50     return ans;
51 }
52 void init()
53 {
54     for(int i=0;i<N;i++)
55         for(int j=0;j<N;j++)
56              Map[i][j]=-INF;
57 }
View Code

题目:

 http://www.cnblogs.com/Potato-lover/category/615224.html

 

三、多重匹配

最大匹配值允许A集合与B集合是一一对应。多重匹配可以使得B的元素与多个A的元素匹配。

算法模版:

 1 const int N=1010;
 2 int cy[N][N],vcy[N];
 3 bool bmask[N],bmap[N][N];
 4 int nx,ny,limit,L,R;
 5 bool findpath(int u)
 6 {
 7     int i,j;
 8     for(i=1;i<=ny;i++)
 9     {
10         if(bmap[u][i]&&!bmask[i])
11         {
12             bmask[i]=1;
13             if(vcy[i]<limit)
14             {
15                 cy[i][++vcy[i]] =u;
16                 return 1;
17             }
18             for(j=1;j<=vcy[i];j++)
19             {
20                 if(findpath(cy[i][j]))
21                 {
22                     cy[i][j]=u;
23                     return 1;
24                 }
25             }
26         }
27     }
28     return 0;
29 }
30 bool mulmatch()
31 {
32     memset(vcy,0,sizeof(vcy));
33     for(int i=1;i<=nx;i++)
34     {
35         memset(bmask,0,sizeof(bmask));
36         if(!findpath(i)) return 0;
37     }
38     return 1;
39 }
40 void init()
41 {
42     memset(bmap,0,sizeof(bmap));
43 }
44 int main()
45 {
46     L=0,R=nx;
47     while(L<=R)
48     {
49         limit=(L+R)/2;
50         if(mulmatch()) R=limit-1;
51         else L=limit+1;
52     }
53     printf("%d\n",L);
54 }
View Code

 题目:

2289  Jamie's Contact Groups

 

四、二分图模型的应用

1、二分图最小点覆盖  http://www.cnblogs.com/Potato-lover/p/3980411.html

2、有向无环图的最小路径覆盖  http://www.cnblogs.com/Potato-lover/p/3989625.html

3、二分图的最大独立集  http://www.cnblogs.com/Potato-lover/p/3980491.html

 

 

posted @ 2014-10-06 17:15  pengmq  阅读(292)  评论(0编辑  收藏  举报