1. 程式人生 > >poj 1325 Machine Schedule(最小頂點覆蓋+最大匹配)

poj 1325 Machine Schedule(最小頂點覆蓋+最大匹配)

http://poj.org/problem?id=1325

題意:有AB兩臺機器和k個任務,機器A有n種模式,機器B有m種模式,初始均工作在模式0,每個任務都可以由機器A的一種模式或機器B的一種模式完成,每次切換模式都需要代價1,要求用最小的代價完成所有任務。

思路:

A的n種模式和B的m種模式自成一個集合,顯然是一個二分圖的模型。令X= {機器A的模式},Y={機器B的模式}, E= {(i,j)| job K 可由機器A的模式i或機器B的模式j完成},這樣構造了一個二分圖G= {X,Y,E}.

本題是一類最小頂點覆蓋的問題,將機器A和機器B的某個工作模式看做頂點,某個任務看做一條邊,那麼問題就轉化為是否存在一個最小規模的點集,使得所有的邊都至少和該點集中的一個頂點關聯。

而二分圖的最小頂點覆蓋問題與最大匹配問題是等價的。由於本題機器AB初始都工作在mode_0,那麼被機器AB的mode_0模式覆蓋的頂點可以不需要額外考慮。

#include <stdio.h>
#include <string.h>
const int maxn = 110;

int map[maxn][maxn];	//鄰接矩陣存二分圖
int chk[maxn];			//記錄點是否被掃描過
int match[maxn];		//儲存匹配方案
int n,m,k;

bool dfs(int p)
{
	for(int i = 0; i < m; i++)
	{
		if(map[p][i] && !chk[i])//找到p的一個對應點且該點沒有被檢查過,(檢查即嘗試過更改i的匹配)
		{
			chk[i] = 1;
			if(match[i] == -1 || dfs(match[i]))//如果i未在匹配中或者i在匹配中但是從與i相鄰的節點出發可以有增廣路
			{
				match[i] = p;//與i匹配的點更改為p
				return true;//多了一條匹配邊
			}
		}
	}
	return false;
}

int main()
{
	while(~scanf("%d",&n))
	{
		if(n == 0) break;
		scanf("%d %d",&m,&k);
		memset(map,0,sizeof(map));
		memset(match,-1,sizeof(match));

		int x,y,z;
		for(int i = 0; i < k; i++)
		{
			scanf("%d %d %d",&x,&y,&z);
			if(y*z != 0)
				map[y][z] = 1;
		}
		
		int res = 0;

		for(int i = 0; i < n; i++)		//對n個點依次進行增廣
		{
			memset(chk,0,sizeof(chk));	//一次增廣中對chk初始化
			if(dfs(i)) res += 1;		//增廣成功,表示i點找到了一個匹配,多了一條匹配邊
		}
		printf("%d\n",res);
	}
	return 0;
}