P1894 [USACO4.2] 完美的牛栏The Perfect Stall 题解

P1894 [USACO4.2] 完美的牛栏The Perfect Stall

这题是我做完 P1640 后做的,因此感觉还不是很难。基本上就是二分图的模版,也比较适合二分图入门的练习。

简化题意

\(n\) 头奶牛与 \(m\) 个牛栏。
\(i\) 头牛希望进入 \(s_i\) 个牛栏中的一个,第 \(i\) 头牛希望进入的第 \(j\) 个牛栏编号为 \(a_{i, j}\)。一头牛只会选择一个它想要进入的牛栏并进入,两头牛不能共用一个牛栏。
求最多能满足几头牛进入它们想要的牛栏。

解题思路

这题很容易看出来,把牛栏与牛之间的关系变为一条边,那么我们就可以获得一张二分图。这时候,我们在构造的二分图上跑二分图最大匹配,求出答案就行了。
我说的可能比较抽象,这里还是拿样例来举例子。
样例:

input:
5 5
2 2 5
3 2 3 4
2 1 5
3 1 2 5
1 2

output:
4

我们把左边的节点设为牛栏的编号,右边的节点设为牛的编号,就可以获得这样一张二分图:
image
对于此二分图,一种最大匹配方案如下:
image
经过这样的样例解释,大家应该可以理解我这个构图的思路了吧。其实就是把牛栏抽象为了左边的节点,牛抽象为了右边的节点,牛对牛栏的喜好抽象为了边而已。
其实,代码基本根模版没有区别。

代码部分

#include <bits/stdc++.h>
using namespace std;
int n, m, ans = 0;
vector<int> g[210];
int match[210];
bool vis[210];
bool dfs(int u)//模版:匈牙利算法求二分图最大匹配 
{
	for(int i = 0;i < g[u].size();i ++)
	{
		int v = g[u][i];
		if(vis[v])
			continue;
		vis[v] = 1;
		if(!match[v] || dfs(match[v]))
		{
			match[v] = u;
			return true;
		}
	}
	return false;
}
int main()
{
	cin >> n >> m;
	for(int i = 1, s;i <= n;i ++)
	{
		cin >> s;
		for(int j = 1, a;j <= s;j ++)
		{
			cin >> a;
			g[a].push_back(i);//把牛对牛栏的喜好抽象为边 
		}
	}
	for(int i = 1;i <= m;i ++)//对于每个牛栏(左边的节点),跑一遍 DFS 
	{
		memset(vis, 0, sizeof(vis));
		if(dfs(i))
			ans ++;
	}
	cout << ans << endl;
	return 0;
}

posted on 2026-03-01 22:09  Leo_29  阅读(17)  评论(0)    收藏  举报

导航