题目来源于:洛谷
题目本质:二分图
虽然本质上是二分图,但我好像没用,我直接食用的匈牙利算法,直接出来了。
(匈牙利算法不太明白的,详见趣写算法系列之--匈牙利算法_匈牙利算法基本原理-CSDN博客)
解题思路:
把牛和牛栏分成两个集合 每只牛可以匹配至少一个牛栏。
先遍历牛,把第一只牛匹配上第一个牛栏,然后再对第二只牛进行匹配。
如果第二只牛可以匹配到第一个牛栏,而这时第一只牛又有另一种匹配选择,那么第二只牛就匹配上第一个牛栏,第一只牛去找另一个牛栏来匹配,以此类推。
代码如下:
#include<bits/stdc++.h>
using namespace std;
const int N=10005;
int n,m,t,ans=0,x_[N],y_[N];
bool flag[1005][1005],vis[N];
//flag记录每只牛可以匹配的牛栏
inline bool find(int x){
for(int i=1;i<=m;i++){
if(flag[x][i]&&!vis[i]){//如果这只牛能匹配上这个牛栏并且这个牛栏没有被其他牛占据
vis[i]=true;
if(y_[i]==-1||find(y_[i]))
//如果这个牛栏没有被占据或者这个牛栏可以腾出来,即原来占据的牛可以找到另一个牛栏
//这里使用递归实现匹配
{
x_[i]=i;
y_[i]=x;
return true;
}
}
}
return false;
}
inline void match(){
memset(x_,-1,sizeof(x_));
memset(y_,-1,sizeof(y_));
for(int i=1;i<=n;i++){
memset(vis,false,sizeof(vis));
ans+=find(i);
//如果匹配成功,find(i)的值为真,即为1
}
}
int main(){
cin>>n>>m;
for(int i=1;i<=n;i++){
cin>>t;
for(int j=1;j<=t;j++){
int x;
cin>>x;
flag[i][x]=true;
//第i只牛可以匹配第x个牛栏
}
}
match();
cout<<ans;
return 0;
}