题目大意
农夫有N头牛,M个坑位,每头牛都只在特定的几个坑位内才能产奶。寻求最大产奶方案。
输入格式
第一行N,M两个数字
接下来N行,每行第一个数字表示该行接下来有几个数字。表示第i头牛在哪些坑位里能产奶
输出格式
输出最大匹配数
样例输入
5 5
2 2 5
3 2 3 4
2 1 5
3 1 2 5
1 2
样例输出
4
题解
二分图模板题。可以用匈牙利算法或者最大流来求解。这里用匈牙利算法来求解。
关于匈牙利算法,送上两篇优秀博客。第一篇生动形象,非常容易理解,第二篇比较严谨。建议按顺序阅读。简单易懂: https://blog.youkuaiyun.com/dark_scope/article/details/8880547
严谨详细:http://www.renfei.org/blog/bipartite-matching.html这两篇博客里的代码还是有所不同的,第一篇的代码更容易理解,更简单,把二分图分成两个独立的部分,在dfs搜索的时候每次都是从二分图的同一个部分向另一部分搜索。第二篇中的代码不区分二分图为两个独立的部分,只是按编号来区分不同的节点,在同一个图中搜索,所以matching的时候要多判断一次,并且引入了更多的概念。实际上原理和最大流都是相通的啊,都是在增广。
代码
#include <iostream>
#include <vector>
#include <cstring>
#define MAXN 510
#define MAXM 510
using namespace std;
int N, M;
vector<int> G[MAXN];
int stall[MAXM];
bool used[MAXM];
bool dfs(int s) {
int len = G[s].size();
for (int i = 0; i < len; i++) {
int v = G[s][i];
if (!used[v]) {
used[v] = true;
if (stall[v] == -1 || dfs(stall[v])) {
stall[v] = s;
return true;
}
}
}
return false;
}
int hungarian() {
int ans = 0;
memset(stall, -1, sizeof(stall));
for (int i = 1; i <= N; i++) {
memset(used, false, sizeof(used));
if (dfs(i)) {
ans++;
}
}
return ans;
}
int main() {
while (cin >> N >> M) {
for (int i = 1; i <= N; i++) {
G[i].clear();
int cnt;
cin >> cnt;
for (int j = 0; j < cnt; j++) {
int the_stall;
cin >> the_stall;
G[i].push_back(the_stall);
}
}
cout << hungarian() << endl;
}
return 0;
}