题目链接:LA 3126 - Taxi Cab Scheme
题目大意:n个客人,从城市的不同位置出发,到达他们的目的地。已知每个人的出发时间hh:mm,出发地点(x1,y1)及目的地(x2,y2),要求使用最少的出租车接送乘客,使得每个顾客的要求都被执行,且每次出租车接客时需要至少提前一分钟到达乘客所在的位置。城区是网格型的,地址用(x,y)表示,出租车从(x1,y1)到(x2,y2)需要行驶|x1 - x2| + |y1 - y2|分钟。
题目分析:本题的模型是DAG上的最小路径覆盖。将每个客人视为一个节点,如果接送完顾客i后还可以继续接送顾客j,则对应DAG中的一条边i -> j。对每个节点拆点为i,i',如果图中存在有向边i -> j,则建边(i,j')。设二分图的最大匹配数为m,则结果即为n - m。
代码如下:
#include <stdio.h>
#include <string.h>
#include <algorithm>
#define abs(X) ((X) > 0 ? (X) : -(X))
#define REP(I, X) for(int I = 0; I < X; ++I)
#define clear(A, X, SIZE) memset(A, X, sizeof(A[0]) * (SIZE + 1))
using namespace std;
const int maxN = 2000;
const int maxE = 1000000;
struct Edge{
int v, n;
}edge[maxE];
struct Node{
int s, e, x1, y1, x2, y2;
}a[maxN];
int adj[maxN], cntE, vis[maxN], link[maxN];
int n;
void addedge(int u, int v){
edge[cntE].v = v; edge[cntE].n = adj[u]; adj[u] = cntE++;
}
int find(int u){
for(int i = adj[u]; ~i; i = edge[i].n) if(!vis[edge[i].v]){
int v = edge[i].v;
vis[v] = 1;
if(link[v] == -1 || find(link[v])){
link[v] = u;
return 1;
}
}
return 0;
}
int match(){
int ans = 0;
clear(link, -1, n);
REP(i, n){
clear(vis, 0, n);
ans += find(i);
}
return ans;
}
void work(){
int h, m;
scanf("%d", &n);
clear(adj, -1, n);
cntE = 0;
REP(i, n){
scanf("%d:%d%d%d%d%d", &h, &m, &a[i].x1, &a[i].y1, &a[i].x2, &a[i].y2);
a[i].s = h * 60 + m;
a[i].e = a[i].s + abs(a[i].x1 - a[i].x2) + abs(a[i].y1 - a[i].y2);
}
REP(i, n) REP(j, n){
if(a[i].e + abs(a[i].x2 - a[j].x1) + abs(a[i].y2 - a[j].y1) < a[j].s) addedge(i, j);
}
printf("%d\n", n - match());
}
int main(){
int t;
for(scanf("%d", &t); t; --t) work();
return 0;
}