对应POJ题目:点击打开链接
Time Limit: 1000MS | Memory Limit: 10000K | |
Total Submissions: 17976 | Accepted: 7086 |
Description
Input
Output
Sample Input
2 3 3 3 1 2 3 2 1 2 1 1 3 3 2 1 3 2 1 3 1 1
Sample Output
YES NO
Source
题意:有P门课和N个学生,一个学生可以选0~p门课,问是否有一个集合包含P个学生,使得该集合里每个学生分别对应P门课,即每门可都有学生对应
思路:二分图求最大匹配模板,就是用个net[i][j]数组,i表示第i门课程,j表示学生ID。这里用DFS和BFS
DFS
#include<cstdio> #include<cstdlib> #include<cmath> #include<map> #include<queue> #include<stack> #include<vector> #include<algorithm> #include<cstring> #include<string> #include<iostream> #define ms(x,y) memset(x,y,sizeof(x)) const int MAXN=300+10; const int INF=1<<30; using namespace std; int link[MAXN]; int vis[MAXN]; int net[MAXN][MAXN]; int left,right; int c,n; int dfs(int u) { for(int v=1; v<=n; v++){ if(!vis[v] && net[u][v]){ vis[v] = 1; if(link[v] == -1 || dfs(link[v])){ link[v] = u; return 1; } } } return 0; } int MaxMatch() { int num=0; ms(link, -1); for(int i=1; i<=c; i++){ ms(vis, 0); if(dfs(i)) num++; } return num; } int main() { //freopen("in.txt","r",stdin); int T; scanf("%d", &T); while(T--) { ms(net,0); scanf("%d%d", &c,&n); if(n < c){ printf("NO\n"); continue; } for(int i=1; i<=c; i++){ int t,m; scanf("%d", &t); for(int j=0; j<t; j++){ scanf("%d", &m); net[i][m] = 1; } } int ans = MaxMatch(); if(ans == c) printf("YES\n"); else printf("NO\n"); } return 0; }
BFS
#include<cstdio> #include<cstdlib> #include<cmath> #include<map> #include<queue> #include<stack> #include<vector> #include<algorithm> #include<cstring> #include<string> #include<iostream> #define ms(x,y) memset(x,y,sizeof(x)) const int MAXN=300+10; const int INF=1<<30; using namespace std; int link_l[MAXN]; int link_r[MAXN]; int vis[MAXN]; int pre[MAXN]; int net[MAXN][MAXN]; int c,n; int MaxMatch() { ms(link_l, -1); ms(link_r, -1); int res = 0; for(int i=1; i<=c; i++){//以左边(即课程)为起点寻找一条增广路 ms(vis, 0);//清空标记 ms(pre, 0);//清空前驱 queue<int>q; q.push(i); int ok=0; while(!q.empty()) { int u = q.front(); q.pop(); for(int v=1; v<=n; v++){ if(!vis[v] && net[u][v]){//在右边(即学生)寻找 vis[v] = 1; if(link_l[v] == -1){//该点还没有匹配 ok = 1; int l = u, r = v; while(l)//利用前驱反转路径 { int tmp = link_r[l]; link_l[r] = l; link_r[l] = r; l = pre[l]; r = tmp; } break;//已经找到增广路,退出 } else{//该点已经匹配 pre[link_l[v]] = u;//记录前驱 q.push(link_l[v]);//继续寻找 } } } if(ok) break;//已经找到增广路,退出 } if(ok) res++;//有增广路,总值加1 } return res; } int main() { //freopen("in.txt","r",stdin); int T; scanf("%d", &T); while(T--) { ms(net,0); scanf("%d%d", &c,&n); if(n < c){ printf("NO\n"); continue; } for(int i=1; i<=c; i++){ int t,m; scanf("%d", &t); for(int j=0; j<t; j++){ scanf("%d", &m); net[i][m] = 1; } } int ans = MaxMatch(); if(ans == c) printf("YES\n"); else printf("NO\n"); } return 0; }