首页 > 代码库 > POJ 3216 Repairing Company(最小路径覆盖)

POJ 3216 Repairing Company(最小路径覆盖)

POJ 3216 Repairing Company

题目链接

题意:有m项任务,每项任务的起始时间,持续时间,和它所在的block已知,且往返每对相邻block之间的时间也知道,问最少需要多少个工人才能完成任务,即x最少是多少

思路:先floyd求出每两个block之间的最小距离,然后就是最小路径覆盖问题,一个任务之后能赶到另一个任务就建边

代码:

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
using namespace std;

const int N = 25;
const int M = 205;
const int INF = 0x3f3f3f3f;

int n, m, q[N][N];
vector<int> g[M];

int in[M], s[M], d[M];

bool judge(int i, int j) {
	return s[i] + d[i] + q[in[i]][in[j]] <= s[j];
}

int left[M], vis[M];

bool dfs(int u) {
	for (int i = 0; i < g[u].size(); i++) {
		int v = g[u][i];
		if (vis[v]) continue;
		vis[v] = 1;
		if (left[v] == -1 || dfs(left[v])) {
			left[v] = u;
			return true;
		}
	}
	return false;
}

int hungary() {
	int ans = 0;
	memset(left, -1, sizeof(left));
	for (int i = 0; i < m; i++) {
		memset(vis, 0, sizeof(vis));
		if (dfs(i)) ans++;
	}
	return ans;
}

int main() {
	while (~scanf("%d%d", &n, &m) && n) {
		for (int i = 1; i <= n; i++)
			for (int j = 1; j <= n; j++) {
				scanf("%d", &q[i][j]);
				if (q[i][j] == -1) q[i][j] = INF;
			}
		for (int k = 1; k <= n; k++) {
			for (int i = 1; i <= n; i++) {
				for (int j = 1; j <= n; j++) {
					q[i][j] = min(q[i][j], q[i][k] + q[k][j]);
				}
			}
		}
		for (int i = 0; i < m; i++) {
			g[i].clear();
			scanf("%d%d%d", &in[i], &s[i], &d[i]);
			for (int j = 0; j < i; j++) {
				if (judge(i, j))
					g[i].push_back(j);
				if (judge(j, i))
					g[j].push_back(i);
			}
		}
		printf("%d\n", m - hungary());
	}
	return 0;
}


POJ 3216 Repairing Company(最小路径覆盖)