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**in,1 \leq b_i \leq m1≤b**im

可能有多组数据。

解析

二分图最小点覆盖。

容易看出,这就是一张二分图,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;
}
posted @ 2019-08-18 11:58  DarkValkyrie  阅读(133)  评论(0编辑  收藏  举报