POJ1325 二分图最小覆盖

题目连接 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;
}
发布了204 篇原创文章 · 获赞 13 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/weixin_43701790/article/details/104592729