裸的二分图匹配
匈牙利算法:
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <vector>
#include <iostream>
using namespace std;
#define N 220
int n, m;
vector<int> adj[N];
int pre[N];
bool used[N];
bool CrossPath(int k) {
for (int i=0; i<adj[k].size(); i++) {
int j=adj[k][i];
if (!used[j]) {
used[j]=true;
if (pre[j]==0 || CrossPath(pre[j])) {
pre[j]=k;
return true;
}
}
}
return false;
}
int hungary() {
int match = 0;
memset(pre, 0, sizeof(pre));
for (int i=1; i<=n; i++) {
memset(used, false, sizeof(used));
if (CrossPath(i))
match++;
}
return match;
}
int main() {
while (scanf("%d%d", &n, &m) == 2) {
int b, c;
for (int i=1; i<=n; i++) {
adj[i].clear();
scanf("%d", &c);
while (c--) {
scanf("%d", &b);
adj[i].push_back(b);
}
}
cout << hungary() << endl;
}
return 0;
}
转化为最大流(这个最大流的模板存储图的方式有点低效了,但是算法整体的时间还是挺不错的):
#include <cstdio>
#include <cstring>
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
#define N 420
#define INF 0x3f3f3f3f
class Dinic {
public:
int c[N][N], n, s, t, l[N], e[N];
int flow(int maxf = INF) {
int left = maxf;
while (build()) left -= push(s, left);
return maxf - left;
}
int push(int x, int f) {
if (x == t) return f;
int &y = e[x], sum = f;
for (; y<n; y++)
if (c[x][y] > 0 && l[x]+1==l[y]) {
int cnt = push(y, min(sum, c[x][y]));
c[x][y] -= cnt;
c[y][x] += cnt;
sum -= cnt;
if (!sum) return f;
}
return f-sum;
}
bool build() {
int m = 0;
memset(l, -1, sizeof(l));
l[e[m++]=s] = 0;
for (int i=0; i<m; i++) for (int y=0; y<n; y++)
if (c[e[i]][y] > 0 && l[y]<0) l[e[m++]=y] = l[e[i]] + 1;
memset(e, 0, sizeof(e));
return l[t] >= 0;
}
} net;
int main() {
int n, m, a, b;
while (scanf("%d%d", &n, &m) == 2) {
memset(net.c, 0, sizeof(net.c));
net.s = 0, net.t = n+m+1, net.n = n+m+2;
for (int i=1; i<=n; i++) net.c[net.s][i] = 1;
for (int i=1; i<=m; i++) net.c[n+i][net.t] = 1;
for (int i=1; i<=n; i++) {
cin >> a;
while (a--) {
cin >> b;
net.c[i][n+b] = INF;
}
}
cout << net.flow() << endl;
}
return 0;
}