题目链接:http://poj.org/problem?id=1469
Time Limit: 1000MS | Memory Limit: 10000K | |
Total Submissions: 14455 | Accepted: 5715 |
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
题意:每门课对应选出一位课代表。
当前课程的课代表必须是这门课程的学生,而且每人只可当一门课程的代表。
算法:二分图的最大匹配【模板题】
分析:分别以课程和学生为点集u、v,对应匹配。
//00K 438MS C++ 1003B #include<cstdio> #include<cstring> const int maxN=310; const int maxP=110; int map[maxP][maxN];//建图 int match[maxN];//匹配连接 bool vis[maxN];//标记 int uN,vN; bool dfs(int u) { for(int v=1;v<=vN;v++)//对应遍历学生 { if(!vis[v] && map[u][v]) { vis[v]=true; if(match[v]==-1 || dfs(match[v])) { match[v]=u; return true; } } } return false; } bool hungary() { int sum=0; memset(match,-1,sizeof(match));//未匹配前,初始化 for(int i=1;i<=uN;i++)//遍历每一门课程 { memset(vis,false,sizeof(vis));//找增广路前初始化 if(dfs(i)) sum++; } if(sum==uN) return true; else return false; } int main() { int test; int p,n; int num_stu,student; while(scanf("%d",&test)!=EOF) { while(test--) { scanf("%d%d",&p,&n); uN=p,vN=n; memset(map,0,sizeof(map)); for(int i=1;i<=p;i++) { scanf("%d",&num_stu);//选这门课的学生人数 for(int j=1;j<=num_stu;j++) { scanf("%d",&student); map[i][student]=1; } } if(hungary()) printf("YES\n"); else printf("NO\n"); } } return 0; }
//300K 438MS C++ 1465B //PS:初次做这种题目时分析的代码。和上面的差不多 #include<stdio.h> #include<string.h> int link[310]; int n,m; int v[310]; int map[110][310]; bool find(int x) { int i; for(i=1;i<=m;i++)//从第一个人开始查找,把第x节课分配给第i个人 { if(!v[i] && map[x][i])//如果第i个人没有被分配课程,并且第i个人选了第x节课 { v[i]=1;//第i个人标记为分配了课程 if(link[i]==0 || find(link[i]))//如果这门课程没有被分配掉 { //或者假如这门课被分配掉了。。然后你看分配的这个学生能不能找到其他选择,有其它选择就把这门课空出来那这个人就可以选了。。 link[i]=x;//标记这门课被选,第i个人选了第x节课 return true; } } } return false; } int main() { int test; int i,j; int x,y; int sum; scanf("%d",&test); while(test--) { sum=0; memset(map,0,sizeof(map)); memset(link,0,sizeof(link)); scanf("%d%d",&n,&m); for(i=1;i<=n;i++) { scanf("%d",&x); for(j=1;j<=x;j++) { scanf("%d",&y); map[i][y]=1;//第y个人可以选第i节课 ,就是加一条i到y的有向边 } } for(i=1;i<=n;i++)//从第一节课开始分配每一节课 { memset(v,false,sizeof(v)); if(find(i))//寻找最大匹配。最大匹配就是要不停地找增广路,所以每次都要初始化,重新再找直到找不到了 sum++; } if(sum==n) printf("YES\n"); else printf("NO\n"); } return 0; }