http://acm.hdu.edu.cn/showproblem.php?pid=1083
题意:一共有N个学生跟P门课程,一个学生可以任意选一门或多门课,问是否达成: 1.每个学生选的都是不同的课(即不能有两个学生选同一门课) 2.每门课都有一个代表(即P门课都被成功选过)
今天学姐讲匹配时讲的题目,初学匹配,对匹配还有很多不理解的地方。。
增广路径性质:
(1)有奇数条边。
(2)起点在二分图的左半边,终点在右半边。
(3)路径上的点一定是一个在左半边,一个在右半边,交替出现。(其实二分图的性质就决定了这一点,因为二分图同一边的点之间没有边相连,不要忘记哦。)
(4)整条路径上没有重复的点。
(5)起点和终点都是目前还没有配对的点,而其它所有点都是已经配好对的。
最小点覆盖=最大匹配
#include <iostream> #include <stdio.h> #include <string.h> #include <string> #include <vector> #include <algorithm> #include <map> #include <queue> #include <stack> #include <math.h>using namespace std;#define met(a, b) memset(a, b, sizeof(a)) #define maxn 303 #define INF 0x3f3f3f3f const int MOD = 1e9+7;typedef long long LL; int v[maxn], used[maxn], G[maxn][maxn]; int p;int Hungary(int x) {for(int i=1; i<=p; i++){if(!v[i] && G[x][i]){v[i] = 1;if(!used[i] || Hungary(used[i])){used[i] = x;return 1;}}}return 0; }int main() {int T, n, cnt, x;scanf("%d", &T);while( T --){met(G, 0);scanf("%d %d", &p, &n);for(int i=1; i<=p; i++){scanf("%d", &cnt);for(int j=1; j<=cnt; j++){scanf("%d", &x);G[x][i] = 1;}}met(used, 0);int ans = 0;for(int i=1; i<=n; i++){met(v, 0);if(Hungary(i))ans ++;}if(ans == p) puts("YES");else puts("NO");}return 0; }