http://poj.org/problem?id=1469
题目是说有几门课程和几个学生,让你求的学生和课程之间的最大匹配数是否和所给的课程数目相等。如果相等输出“YES” 否则,输出“NO“
下面这就是一个二分图
二分图又称作二部图,是图论中的一种特殊模型。 设G=(V,E)是一个无向图,如果顶点V可分割为两个互不相交的子集(A,B),并且图中的每条边(i,j)所关联的两个顶点i和j分别属于这两个不同的顶点集(i in A,j in B),则称图G为一个二分图。 简而言之,就是顶点集V可分割为两个互不相交的子集,并且图中每条边依附的两个顶点都分属于这两个互不相交的子集。给定一个二分图G,在G的一个子图M中,M的边集中的任意两条边都不依附于同一个顶点,则称M是一个匹配. 选择这样的边数最大的子集称为图的最大匹配问题(maximal matching problem)
求二分图的最大匹配的算法就是匈牙利算法 这里有详细的讲解,可以去看一下http://hi.baidu.com/ensteinniesen/blog/item/7ea41aeaa0c783c1d539c94a.html
匈牙利算法的模板
1 二分图最大匹配问题的匈牙利算法:
2
3 #define N 202
4 int useif[N]; //记录y中节点是否使用
5 int link[N]; //记录当前与y节点相连的x的节点
6 int mat[N][N]; //记录连接x和y的边,如果i和j之间有边则为1,否则为0
7 int gn,gm; //二分图中x和y中点的数目
8 int can(int t)
9 {
10 int i;
11 for(i=1;i<=gm;i++)
12 {
13 if(useif[i]==0 && mat[t][i])
14 {
15 useif[i]=1;
16 if(link[i]==-1 || can(link[i]))
17 {
18 link[i]=t;
19 return 1;
20 }
21 }
22 }
23 return 0;
24 }
25 int MaxMatch()
26
27 {
28 int i,num;
29 num=0;
30 memset(link,0xff,sizeof(link));
31 for(i=1;i<=gn;i++)
32 {
33 memset(useif,0,sizeof(useif));
34 if(can(i)) num++;
35 }
36 return num;
37 }
下面就是这道题目的代码了
1 #include<stdio.h>
2 #include<string.h>
3 #include<iostream>
4 using namespace std;
5 #define M 300
6 int map[M][M],v[M],m[M];
7 int p,n;
8 int match(int k)
9 {
10 int i;
11 for(i=1;i<=n;i++)
12 {
13 if(map[k][i]&&!v[i])
14 {
15 v[i]=1;
16 if(m[i]==-1||match(m[i]))
17 {
18 m[i]=k;
19 return 1;
20 }
21 }
22 }
23 return 0;
24 }
25 int main()
26 {
27 int t,i;
28 cin>>t;
29 while(t--)
30 {
31 memset(map,0,sizeof(map));
32 memset(m,-1,sizeof(m));
33 cin>>p>>n;
34 int k,x;
35 for(i=1;i<=p;i++)
36 {
37 scanf("%d",&k);//cin>>k;
38 while(k--)
39 {
40 scanf("%d",&x);
41 //cin>>x;
42 map[i][x]=1;
43 }
44 }
45 int sum=0;
46 for(i=1;i<=p;i++)
47 {
48 memset(v,0,sizeof(v));
49 if(match(i)) sum++;
50 }
51 if(sum==p) cout<<"YES\n";
52 else cout<<"NO\n";
53 }
54 return 0;
55 }