UVA1194 Machine Schedule[二分图最小点覆盖]
题意翻译
有两台机器 A,B 分别有 n,m 种模式。
现在有 k 个任务。对于每个任务 i ,给定两个整数$ a_i\(和\) b_i$,表示如果该任务在 A上执行,需要设置模式为 \(a_i\);如果该任务在 B** 上执行,需要设置模式为$ b_i$。
每台机器第一次开机默认处在0模式,且第一次开机不需要消耗时间。任务可以以任意顺序被执行,但每台机器转换一次模式就要重启一次。求怎样分配任务并合理安排顺序,能使机器重启次数最少。
1 \leq n,m \leq 1001≤n,m≤100,1 \leq k \leq 10001≤k≤1000,1 \leq a_i \leq n1≤a**i≤n,1 \leq b_i \leq m1≤b**i≤m。
可能有多组数据。
解析
二分图最小点覆盖。
容易看出,这就是一张二分图,A、B的不同模式分别是左部和右部的点。
我们要解决的问题是,对于任意一个任务,我们可以把它看作一条边。对于这条边,我们必须要选择二分图中任意一部的点,即最小点覆盖。
定理
二分图最小点覆盖包含点数=二分图最大匹配数
根据这个定理,我们用匈牙利求最大匹配就行。
参考代码
#include<cstdio>
#include<iostream>
#include<cmath>
#include<cstring>
#include<ctime>
#include<cstdlib>
#include<algorithm>
#include<queue>
#include<set>
#include<map>
#include<bitset>
#define N 1010
using namespace std;
int n,m,k,f[N];
vector<int> g[N];
bitset<N> v;
inline bool dfs(int x)
{
for(int i=0;i<g[x].size();++i){
int y=g[x][i];
if(v[y]) continue;
v[y]=1;
if(!f[y]||dfs(f[y])){
f[y]=x;
return 1;
}
}
return 0;
}
int main()
{
while(~scanf("%d",&n)&&n!=0){
for(int i=1;i<=n;++i) g[i].clear();
v.reset();memset(f,0,sizeof(f));
scanf("%d%d",&m,&k);
while(k--){
int num,u,v;
scanf("%d%d%d",&num,&u,&v);
g[u].push_back(v+n),g[v+n].push_back(u);
}
getchar();
int ans=0;
for(int i=1;i<=n;++i){
v.reset();ans+=dfs(i);
}
cout<<ans<<endl;
}
return 0;
}