裸的二分图匹配
匈牙利算法:
#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; }