测试地址:Courses
题目大意:有P门课程和N个学生,要求从这些学生中取出P个组成委员会,要求:(1)委员会中的每个学生都代表不一样的课程(一个学生上一门课程,他就可以代表这门课程)。(2)委员会中每门课程都有不同的学生代表。问存不存在这样的委员会组建方案。
做法:裸的二分图最大匹配,这里直接套Hungary(匈牙利)算法即可。
2017.3.7更新:用理论上更优的Hopcroft-Karp算法又做了一遍,一并贴在这里。
以下是本人代码:
Hungary(匈牙利)算法:
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
int T,n,p,tot=0,match,first[110],mat[310];
struct {int v,next;} e[100010];
bool used[310];
void insert(int a,int b)
{
e[++tot].v=b;
e[tot].next=first[a];
first[a]=tot;
}
bool crosspath(int x) //返回一个布尔值,表示存不存在从x出发的交错链
{
for(int i=first[x];i;i=e[i].next)
{
int j=e[i].v;
if (!used[j])
{
used[j]=1;
if (mat[j]==0||crosspath(mat[j]))
{
mat[j]=x;
return 1;
}
}
}
return 0;
}
void hungary() //Hungary(匈牙利)算法
{
for(int i=1;i<=p;i++)
{
memset(used,0,sizeof(used));
if (crosspath(i))
match++;
}
}
int main()
{
scanf("%d",&T);
while(T--)
{
scanf("%d%d",&p,&n);
memset(first,0,sizeof(first));
memset(mat,0,sizeof(mat));
match=tot=0;
for(int i=1;i<=p;i++)
{
int cnt;
scanf("%d",&cnt);
while(cnt--)
{
int a;
scanf("%d",&a);
insert(i,a);
}
}
if (p>n) {printf("NO
");continue;} //课程数多于学生数,不可能有满足条件的方案
hungary();
if (p==match) printf("YES
");
else printf("NO
");
}
return 0;
}
Hopcroft-Karp算法:
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <queue>
#define inf 999999999
using namespace std;
int p,n,dis,T;
int bmap[110][310];
int cx[110],cy[310],dx[110],dy[310];
bool vis[310];
bool searchpath()
{
queue<int> q;
dis=inf;
memset(dx,-1,sizeof(dx));
memset(dy,-1,sizeof(dy));
for(int i=1;i<=p;i++)
{
if (cx[i]==-1)
{
q.push(i);
dx[i]=0;
}
}
while(!q.empty())
{
int u=q.front();q.pop();
if (dx[u]>dis) break;
for(int i=1;i<=n;i++)
{
if (bmap[u][i]&&dy[i]==-1)
{
dy[i]=dx[u]+1;
if (cy[i]==-1) dis=dy[i];
else
{
dx[cy[i]]=dy[i]+1;
q.push(cy[i]);
}
}
}
}
return dis!=inf;
}
int findpath(int u)
{
for(int i=1;i<=n;i++)
{
if (!vis[i]&&bmap[u][i]&&dy[i]==dx[u]+1)
{
vis[i]=1;
if (cy[i]!=-1&&dy[i]==dis)
{
continue;
}
if (cy[i]==-1||findpath(cy[i]))
{
cy[i]=u,cx[u]=i;
return 1;
}
}
}
return 0;
}
int maxmatch()
{
int ans=0;
memset(cx,-1,sizeof(cx));
memset(cy,-1,sizeof(cy));
while(searchpath())
{
memset(vis,0,sizeof(vis));
for(int i=1;i<=p;i++)
{
if (cx[i]==-1)
{
ans+=findpath(i);
}
}
}
return ans;
}
int main()
{
scanf("%d",&T);
while(T--)
{
scanf("%d%d",&p,&n);
memset(bmap,0,sizeof(bmap));
for(int i=1,k;i<=p;i++)
{
scanf("%d",&k);
for(int j=1,a;j<=k;j++)
{
scanf("%d",&a);
bmap[i][a]=1;
}
}
if (maxmatch()==p) printf("YES
");
else printf("NO
");
}
return 0;
}