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");

 

 

你可能感兴趣的:(poj)