题意:
有n个顾客做出租车,给出每个人的出发时间,出发地与目的地的坐标,问最少要多少辆出租车能满足需要。
两地的距离为两地的曼哈顿距离,出租车一分钟可以行驶距离1。
读入数据按照出发时间升序给出。
思路:
对于两个顾客i和他前面的某个顾客j,如果i到达目的地的时间,加上从i的目的地到j的出发地的时间小于j的出发时间,i和j就能用一辆车满足。
所以,对于每个顾客i,枚举他前面的每一个顾客j,如果i和j能用一辆车满足,就从j到i连一条有向边,题目就转化成了最小路径覆盖问题。
最小路径覆盖=点数-最大匹配数
代码(1240K,79MS):
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <iostream>
#include <vector>
using namespace std;
struct Point{
int x, y;
Point() {}
Point(int a, int b) : x(a), y(b) {}
};
int T;
int n;
int tim[505];
int dist[505];
int mat[505];
int vis[505];
Point endPoint[505];
vector<int> edges[505];
// 两地的曼哈顿距离
int getDist(int x1, int y1, int x2, int y2) {
return abs(x2 - x1) + abs(y2 - y1);
}
bool dfs(int k) {
for (int i = 0; i < edges[k].size(); i++) {
int j = edges[k][i];
if (!vis[j]) {
vis[j] = 1;
if (!mat[j] || dfs(mat[j])) {
mat[j] = k;
return true;
}
}
}
return false;
}
int match() {
int ans = 0;
for (int i = 1; i <= n; i++) {
memset(vis, 0, sizeof(vis));
if (dfs(i)) ans++;
}
return ans;
}
int main() {
scanf("%d", &T);
while (T--) {
scanf("%d", &n);
int h, m;
int x1, y1, x2, y2;
for (int i = 1; i <= n; i++)
edges[i].clear();
for (int i = 1; i <= n; i++) {
scanf("%d:%d", &h, &m);
scanf("%d %d %d %d", &x1, &y1, &x2, &y2);
endPoint[i] = Point(x2, y2); // 目的地
tim[i] = h * 60 + m; // 出发时间
dist[i] = getDist(x1, y1, x2, y2); // 从出发地到目的地的距离
for (int j = 1; j < i; j++) {
if (dist[j] + getDist(endPoint[j].x, endPoint[j].y, x1, y1) + tim[j] < tim[i])
edges[j].push_back(i);
}
}
memset(mat, 0, sizeof(mat));
int ans = n - match();
printf("%d\n", ans);
}
return 0;
}