题目连接 http://poj.org/problem?id=1325
题目大意:
有两台机器 A,B 以及 K 个任务。
机器 A 有 N 种不同的模式(模式0~N-1),机器 B 有 M 种不同的模式(模式0~M-1)。
两台机器最开始都处于模式0。
每个任务既可以在A上执行,也可以在B上执行。
对于每个任务 i,给定两个整数 a[i] 和 b[i],表示如果该任务在 A 上执行,需要设置模式为 a[i],如果在 B 上执行,需要模式为 b[i]。
任务可以以任意顺序被执行,但每台机器转换一次模式就要重启一次。
求怎样分配任务并合理安排顺序,能使机器重启次数最少。
思路:
对于一个任务,可以在A中以模式a[i]做,或者B中以模式b[i]中做,但是只在其中一个做了就行了。可以抽象成一条边,边的两个端点就是a[i]和b[i],只需要有一个点满足即可。对于A和B可以看作二分图的两个部分,边就是二分图中的边了,有一个点满足,相当于二分图中的边的两个点有一个被覆盖即可,可以看出这是一个二分图的最小覆盖。直接求最小覆盖就好了。
最小覆盖=最大匹配。直接匈牙利算法求最大匹配即可。
#include <cstring>
#include <cstdio>
#include <cstdlib>
#include <iostream>
#define mem(a, b) memset(a, b, sizeof a)
using namespace std;
const int N = 2010;
int head[N], nex[N], to[N];
int cnt, n, m, k;
int match[1100];
bool vis[1100];
inline void add(int x, int y){
++cnt;
to[cnt] = y;
nex[cnt] = head[x];
head[x] = cnt;
}
bool dfs(int x){
for (int i = head[x]; i != -1; i = nex[i]){
int y = to[i];
if (vis[y])continue;
vis[y] = 1;
if (match[y] == -1 || dfs(match[y])){
match[y] = x;
return 1;
}
}
return 0;
}
int solve(){
int ans = 0;
for (int i = 0; i < n; i++){
mem(vis, 0);
if (dfs(i))ans++;
}
return ans;
}
int main()
{
while (~scanf("%d", &n) && n){
mem(match, -1);
mem(head, -1);
mem(nex, -1);
cnt = 0;
scanf("%d %d", &m, &k);
for (int i = 0; i < k; i++){
int x, y, z;
scanf("%d %d %d", &x, &y, &z);
if (y && z){
add(y, z + 110);
add(z + 110, y);
}
}
printf("%d\n", solve());
}
return 0;
}