Luogu 1894 [USACO4.2]完美的牛栏The Perfect Stall / POJ 1274 The Perfect Stall(二分图最大匹配)

Description

农夫约翰上个星期刚刚建好了他的新牛棚,他使用了最新的挤奶技术。不幸的是,由于工程问题,每个牛栏都不一样。第一个星期,农夫约翰随便地让奶牛们进入牛栏,但是问题很快地显露出来:每头奶牛都只愿意在她们喜欢的那些牛栏中产奶。上个星期,农夫约翰刚刚收集到了奶牛们的爱好的信息(每头奶牛喜欢在哪些牛栏产奶)。一个牛栏只能容纳一头奶牛,当然,一头奶牛只能在一个牛栏中产奶。

给出奶牛们的爱好的信息,计算最大分配方案。

Input

第一行 两个整数,N (0 <= N <= 200) 和 M (0 <= M <= 200) 。N 是农夫约翰的奶牛数量,M 是新牛棚的牛栏数量。

第二行到第N+1行 一共 N 行,每行对应一只奶牛。第一个数字 (Si) 是这头奶牛愿意在其中产奶的牛栏的数目 (0 <= Si <= M)。后面的 Si 个数表示这些牛栏的编号。牛栏的编号限定在区间 (1..M) 中,在同一行,一个牛栏不会被列出两次。

Output

只有一行。输出一个整数,表示最多能分配到的牛栏的数量.

Sample Input

5 5

2 2 5

3 2 3 4

2 1 5

3 1 2 5

1 2

Sample Output

4

Http

Luogu:https://www.luogu.org/problem/show?pid=1894

POJ:https://vjudge.net/problem/POJ-1274

Source

二分图最大匹配

解决思路

这是一道二分图最大匹配的模板题。

对于一只牛和其喜欢的牛棚,我们连一条有向边。我们定义对于牛棚u,Match[u]为其匹配的牛的编号。

我们依次枚举每一只牛u来修改匹配。当找到一个可以匹配的空牛棚时,我们就直接将该空牛棚的Match值置为该牛u。若该牛棚已经被匹配,那么我们向下dfs该牛棚之前对应的那只牛v,看看能否让其更改匹配,对于牛v的操作与牛u类似,但要注意不要dfs重复的牛。重复上述过程直到为牛u腾出位置,则把该牛棚的Match置为牛u,或不存在解则返回0。更多细节请参看代码。

注意,POJ有多组数据

代码

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<vector>
using namespace std; const int maxN=300;
const int inf=2147483647; int n,m;
vector<int> E[maxN];//存边
bool vis[maxN];//牛棚是否已经访问过,避免重复
int Match[maxN];//存下牛棚匹配的牛的编号,-1表示还未匹配 bool dfs(int u); int main()
{
while(cin>>n>>m)
{
for (int i=1;i<=n;i++)
E[i].clear();
for (int i=1;i<=n;i++)
{
int S;
cin>>S;
for (int j=1;j<=S;j++)
{
int x;
cin>>x;
E[i].push_back(x);//连边
}
} memset(Match,-1,sizeof(Match));
int cnt=0;
for (int i=1;i<=n;i++)
{
memset(vis,0,sizeof(vis));//每一次进行匹配之前都要清空
if (dfs(i))//若成功匹配,则最大匹配数+1,因为多有一个点能够匹配
cnt++;
}
cout<<cnt<<endl;
}
return 0;
} bool dfs(int u)//1表示匹配成功,0表示不成功
{
for (int i=0;i<E[u].size();i++)
{
int v=E[u][i];
if (vis[v]==0)
{
vis[v]=1;
if ((Match[v]==-1) || dfs(Match[v]))//若当前牛棚可以匹配,或是dfs返回1(说明在dfs中成功匹配了),则此时要将新的值更新进去,同时向上一级dfs传值1
{
Match[v]=u;
return 1;
}
}
}
return 0;
}
04-30 05:29