Poj1469_匈牙利算法_最大二分匹配

这道题是一个基本的匈牙利算法,求最大二分匹配。之前在算法导论中学习网络流,明白了网络流中的残留网络,增光路和割,但是去模拟书上的伪代码感觉很是费力。就打算从最基本的匈牙利算法做起。

下面先介绍一下匈牙利算法:

该算法的核心就是寻找增广路径,它是一种用增广路径求二分图最大匹配的算法:

匹配是边集的子集。

设M是图G的一个匹配,需要掌握一下几个概念:

1.M-交错路:M-交错路是一条通路,这条通路中的边为属于M与不属于M但属于G的边交替出现。

2.M-饱和点:M-饱和点是与M中的某条边相关联的点。否则是非M-饱和点。

3.M-可增广路:M-交错路的起点和终点都是非M-饱和点。

设P是M-可增广路,则可以得出以下三个结论:

1.p的路径个数为奇数,并且首尾两条边是不属于M

2.p取反可以得到更大的匹配。

3.M是最大匹配当且仅当不存在M的增广路径。

所以算法就是不断的找出增广路径,知道找不出为止。

 

这道题我用的数据结构是二维数组,这样的话,设n为人数,p为课程数.

空间复杂度为O(n^2),而时间复杂度为o(p*n*n),其中最坏情况下寻找增广路的时间复杂度为o(n)。

以后再给出用邻接表的分析。

需要注意的是,读题的时候以为课程数和学生数要相等,但后来仔细读题发现Each student visits zero, one or more than one courses.说明可以有学生不匹配某个课程。这样看来结果就清楚了,得出的最大二分匹配与课程数比较即可。

还有就是这么多数据的读入,用cin会超时的,之前也遇到这样的问题,好在这次没有在这上面出bug。

以下是代码:

View Code
 1 #include <iostream>
 2 #include <string>
 3 #include <memory.h>
 4 #include <stdio.h>
 5 using namespace std;
 6 bool array[101][301];
 7 int res[301];
 8 bool use[301];
 9 int p,n;
10 
11 bool find(int i)
12 {
13     int j;
14     for(j=1;j<=n;j++)
15     {
16         if(array[i][j] && !use[j])
17         {
18             use[j]=true;
19             if(res[j]==0 || find(res[j]))
20             {
21                 res[j]=i;
22                 return true;
23             }
24         }
25     }
26     return false;
27 }
28 
29 int main()
30 {
31     int num;
32     scanf("%d",&num);
33     int i,j,m,temp;
34     int result;
35     while(num--)
36     {
37         memset(array,0,sizeof(array));
38         memset(res,0,sizeof(res));
39         scanf("%d%d",&p,&n);
40         for(i=1;i<=p;i++)
41         {
42             scanf("%d",&m);
43             for(j=1;j<=m;j++)
44             {
45                 scanf("%d",&temp);
46                 array[i][temp]=true;
47             }
48         }
49 
50         result=0;
51         for(i=1;i<=p;i++)
52         {
53             memset(use,false,sizeof(use));
54             if(find(i))
55                 result++;
56         }
57         if(result==p)
58             printf("YES\n");
59         else
60             printf("NO\n");
61     }
62     return 0;
63 }

这个题也是tju oj1050

这个题有一个小小的优化:

题目要求找对课程的完全匹配,当对课程进行遍历的时候,如果某个课程找匹配失败,就可以结束遍历。

View Code
 1 for(i=1;i<=p;i++)
 2         {
 3             memset(use,false,sizeof(use));
 4             if(!find(i))
 5             {
 6                 printf("NO\n");
 7                 break;
 8             }
 9         }
10         if(i==p+1)
11             printf("YES\n");

 

 

posted @ 2012-07-13 21:49  pushing my way  阅读(865)  评论(0编辑  收藏  举报