题目链接: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; }