题目
农夫约翰上周刚刚建好了新的牛棚,并引进了最新的挤奶技术。
不幸的是,由于工程问题,牛棚中的每个单间都不太一样。
第一周,约翰将奶牛们随机分配在了各个单间中。
但是很快他就发现,每头奶牛都只愿意在一部分自己喜欢的单间中产奶。
在过去的一周中,农夫约翰一直在收集有关哪些奶牛愿意在哪些单间产奶的数据。
一个单间只能分配给一头奶牛,当然,一头奶牛也可能只愿意在一个单间中产奶。
给定奶牛的住宿喜好,请你计算,通过合理分配奶牛的住所,最多能够让多少奶牛可以住在自己愿意产奶的单间中。
输入格式
第一行包含两个整数 和 ,分别表示奶牛的数量以及单间的数量。
接下来 行,每行记录一个奶牛愿意产奶的单间信息。首先包含一个整数 ,表示这头奶牛愿意在 个单间中产奶。接下来包含 个不同的整数,表示这些单间的编号。
所有单间的编号为 。
输出格式
输出一个整数,表示可以被分配在自己愿意产奶的单间中的奶牛的最大数量。
数据范围
输入样例:
5 5
2 2 5
3 2 3 4
2 1 5
3 1 2 5
1 2
输出样例:
4
解题
方法一:匈牙利算法
思路
求二分图最大匹配裸题,详见匈牙利算法求二分图最大匹配。
代码
import java.util.*;
import java.io.*;
public class Main {
static int n, m, N, M;
static int[] h, e, ne;
static int idx;
static int[] matchs;
static boolean[] vis;
static void add(int a, int b) {
e[idx] = b;
ne[idx] = h[a] ;
h[a] = idx++;
}
static boolean find(int u) {
for (int i = h[u]; i != -1; i = ne[i]) {
int v = e[i];
if (!vis[v]) {
vis[v] = true;
if (matchs[v] == 0 || find(matchs[v])) {
matchs[v] = u;
return true;
}
}
}
return false;
}
public static void main(String[] args) throws IOException {
StreamTokenizer in = new StreamTokenizer(new BufferedReader(new InputStreamReader(System.in)));
in.nextToken();
n = (int) in.nval;
in.nextToken();
m = (int) in.nval;
N = Math.max(n, m) + 1;
M = m * m;
h = new int[N];
Arrays.fill(h, -1);
e = new int[M];
ne = new int[M];
for (int u = 1; u <= n; ++u) {
in.nextToken();
int s = (int) in.nval;
while (s-- > 0) {
in.nextToken();
int v = (int) in.nval;
add(u, v);
}
}
matchs = new int[N];
vis = new boolean[N];
int ans = 0;
for (int u = 1; u <= n; ++u) {
Arrays.fill(vis, false);
if (find(u)) ++ans;
}
System.out.println(ans);
}
}
#include <iostream>
#include <cstring>
using namespace std;
const int N = 210, M = N * N;
int n1, n2, heads[M], vals[M], nexts[M], idx;
int matchs[N];
bool vis[N];
void add(int a, int b) {
vals[idx] = b, nexts[idx] = heads[a], heads[a] = idx++;
}
bool find(int u) {
for (int i = heads[u]; i != -1; i = nexts[i]) {
int v = vals[i];
if (!vis[v]) {
vis[v] = true;
if (!matchs[v] || find(matchs[v])) {
matchs[v] = u;
return true;
}
}
}
return false;
}
int main() {
memset(heads, -1, sizeof(heads));
scanf("%d%d", &n1, &n2);
for (int u = 1; u <= n1; ++u) {
int k, v;
scanf("%d", &k);
while (k--) {
scanf("%d", &v);
add(u, v);
}
}
int ans = 0;
for (int i = 1; i <= n1; ++i) {
memset(vis, false, sizeof(vis));
if (find(i)) ++ans;
}
printf("%d\n", ans);
return 0;
}
评论区