又见版刷题。。。
本题如何构造二部图?
把A的n个mode和B的m个mode看做图的顶点,然后如果某个人物可以再A的mode_i或者B的mode_j上完成,则连一个边。机器模式编号无关紧要,关键的是从不同的模式之间切换需要连线。本题求的是,最小的顶点(模式)集合,覆盖(该模式完成的任务)尽可能多的边(转换模式——减少转换模式)。
上一篇日志中有一个重要的知识点,二部图的最小点覆盖数等于最大匹配数。
那么这又是一个模板题了。
#include <iostream> using namespace std; #define MAXN 105 #define _clr(x) memset(x,0xff,sizeof(int)*MAXN) int map[MAXN][MAXN]; int match1[MAXN], match2[MAXN];// the bipartite graph's two part... int hungary(int m, int n, int mat[][MAXN], int* match1, int* match2)//m for big { int s[MAXN], t[MAXN], p, q, ret = 0, i, j, k; for (_clr(match1), _clr(match2), i = 1; i <= m; ret += (match1[i++] >= 0)) for (_clr(t), s[p = q = 0] = i; p <= q&&match1[i] < 0; p++) for (k = s[p], j = 1; j <= n&&match1[i] < 0; j++) if (mat[k][j] && t[j] < 0) { s[++q] = match2[j], t[j] = k; if (s[q] < 0) for (p = j; p >= 0; j = p) match2[j] = k = t[j], p = match1[k], match1[k] = j; } return ret; } int main() { int n, m, k; while (cin >> n) { if (n == 0) break; cin >> m >> k; memset(map, 0, sizeof(map)); for (int i = 0; i < k; i++) { int temp, a, b; cin >> temp >> a >> b; map[a][b] = 1; } cout << hungary(n, m, map, match1, match2) << endl; } return 0; } |