Description
Hint
- (1le n, mle 100)
- (1le kle 10^3)
- (0le a_i < n, 0le b_i<m)
Solution
把 (A) 的 (n) 个模式视作 (n) 个 (x) 部的点, 把 (B) 的 (m) 个模式视作 (m) 个 (y) 部的点,把一个任务的属性 ((a_i, b_i)) 抽象成一条连接 (x) 部的第 (a_i) 个点,(y) 部的第 (b_i) 个点的边。
于是构成了一张 二分图。
本题有一个要素,即每个任务要么在 (A) 上的 (a_i) 模式执行,要么在 (B) 上的 (b_i) 模式上执行。
转化成二分图的语言: 一条边的两个端点至少选择其中一个。
题目又要求重启尽可能少,于是就要 选择尽量少的点。
显然就是 二分图最小点覆盖 问题,可以用匈牙利算法在 (O(nm)) 的时间内通过本题。
注意,初始状态为模式 0,注意不用算进去。
Hint
/*
* Author : _Wallace_
* Source : https://www.cnblogs.com/-Wallace-/
* Problem : HDU 1150 UVA 1194 Machine Schedule
*/
#include <cstdio>
#include <vector>
#include <cstring>
using namespace std;
const int N = 105;
int n, m, k;
vector<int> G[N];
int match[N], vis[N];
bool Dfs(int x, int t) {
if (vis[x] == t) return false;
vis[x] = t;
for (auto y : G[x]) if (match[y] == -1 || Dfs(match[y], t))
return match[y] = x, true;
return false;
}
void solve() {
memset(vis, 0, sizeof vis);
memset(match, -1, sizeof match);
for (register int i = 0; i < n; i++)
G[i].clear();
for (register int i = 0, a, b; i < k; i++) {
scanf("%d%d%d", &i, &a, &b);
G[a].push_back(b);
}
int ans = 0;
for (register int i = 1; i < n; i++)
ans += int(Dfs(i, i));
printf("%d
", ans);
}
signed main() {
while (scanf("%d", &n) != EOF && n)
scanf("%d%d", &m, &k), solve();
return 0;
}