Machine Schedule
二分图匹配题目。首先是建图方式:如果两台机器分别在模式xk1 , yk2下能完成相同的工作,那么这两个模式连一条边。这样的话,每完成一个工作就相当于将图中的一条边给完成。这样问题就转化为寻找最少的点来看住所有的边,也就是最小点覆盖问题。
最小点覆盖问题:
最小点的覆盖也是图的顶点集的一个子集,如果我们选中一个点,则称这个点将以他为端点的所有边都覆盖了。将图中所有的边都覆盖所用顶点数最少,这个集合就是最小的点的覆盖。最小点覆盖数=最大匹配数。证明可以看刘汝佳的黑书。
在这个题目中,由于开始的时候是处在模式0下,那么在该模式下的所有工作,都不需要切换,在建图的时候如果遇到有需要在模式0下工作的工作不需要添加到图中。然后直接使用匈牙利算法就可以了。
#include <iostream>
#include <stdio.h>
#include <string.h>
#include <vector>
using namespace std ;
const int maxn = 105 ;
bool map [maxn][maxn] ;
bool mark[maxn] ;
int nx[maxn] ;
int ny[maxn] ;
int n ;
int m ;
int k ;
void init(){
memset(map , 0 , sizeof(map)) ;
memset(nx , -1 , sizeof(nx)) ;
memset(ny , -1 , sizeof(ny)) ;
}
void input(){
int i ;
int j ;
int x , y , w ;
scanf("%d%d" , &m , &k) ;
init() ;
for(i = 1 ; i <= k ; i ++){
scanf("%d%d%d" , &x , &y , &w) ;
if(y && w){
map[y][w] = 1 ;
}
}
}
int dfs(int v){
int u ;
for(u = 1 ; u < m ; u ++){
if(!mark[u] && map[v][u]){
mark[u] = 1 ;
if( ny[u] == -1 || dfs(ny[u]) ){
ny[u] = v ;
nx[v] = u ;
return 1 ;
}
}
}
return 0 ;
}
int max_match(){
int ans = 0 ;
for(int i = 1 ; i < n ; i ++){
if(nx[i] == -1){
memset(mark , 0 , sizeof(mark)) ;
ans += dfs(i) ;
}
}
return ans ;
}
int main(){
while(scanf("%d" , &n) , n){
input() ;
printf("%d\n" , max_match()) ;
}
return 0 ;
}