HDU 1150 Machine Schedule (二分图的最小点覆盖)

题目链接:点击打开链接

题意:有A,B两台机器和k给任务,机器A有n中模式,机器B有m种模式,初始均在模式0,每个任务都可以由机器A的一种模式或者机器B的一种模式执行。每次切换模式都需要代价1,要求求最小的代价执行完所有的任务。

题解:最小点覆盖 = 最大匹配数。

感性理解过程:

假设二分图分为(X,Y;E)那么针对于任意点,都有如下两种情况

(1)点 i 同时连接着未匹配的点 和 匹配点

(2)点 i 连接匹配的点

若符合(1)那么我们会选择该点,因为我们若不选择该点,那么与该点连接的未匹配点将需要额外再去选择他。

若符合(2)那么我们选择该点或者选择该点连接的那个匹配点均可。

如图


设红线为一个最大匹配数,对与未匹配的y1而言覆盖他有两种方法,选择x1,或者选择自己本身。若选择y1我们想覆盖y2就需要在选择y2,那么总选择数就变成了4,若选择x1那么我们既覆盖了y1和y2.

所以对匹配边上的点而言,我们会发现我们的选择策略是判断该点是否连接着未匹配点。而正因为是匹配边上的点,所以你选择了其一那么必定会覆盖这条边上的两个点。那由这两条就可以看出来 最小点覆盖 == 最大匹配数。

代码如下


#include<bits/stdc++.h>
using namespace std;

const int N = 105;
int g[N][N];
int a[N],b[N],vis[N];
int n,m,k,ans;

int dfs(int i){
	for(int j = 1 ; j < m ; j ++){
		if(g[i][j] && !vis[j]){
			vis[j] = 1;
			if(b[j] == -1 || dfs(b[j])){
				a[i] = j;
				b[j] = i;
				return 1;
			}
		}
	}
	return 0;
}
int main(){
	int u,v,t;
	while(scanf("%d",&n),n){
		memset(g,0,sizeof(g));
		scanf("%d%d",&m,&k);
		for(int i = 0 ; i < k ; i ++){
			scanf("%d%d%d",&t,&u,&v);
			g[u][v] = 1;
		}
		ans = 0;
		memset(a,-1,sizeof(a));
		memset(b,-1,sizeof(b));
		for(int i = 1 ; i < n ; i ++){
			if(a[i] == -1){
				memset(vis,0,sizeof(vis));
				ans += dfs(i);
			}
		}
		cout << ans << endl;
	}
	return 0;
}

猜你喜欢

转载自blog.csdn.net/pk__pk/article/details/81061167