题意:有m个顾客,每个有开始时间(xx:xx),起点(a,b)与终点(c,d)。拉完这个顾客所需时间是|a-c|+|b-d|分钟。一个车在一天(00:00 to 23:59)之内可能做完i任务之后又能做j任务(条件见原题),问最少需要多少辆出租出能满足所有的乘客。
思路:这道题和算法设计中第7章网络流的第9节(Airline Scheduling)相似。记得当时课上老师给出了另一种做法,即用n减去最大匹配的值。实际上确实如此,如果拉完第i个顾客还能拉第j个顾客,那么在i和j之间连一条边。有人管这个叫做最小路径覆盖。
#include <stdio.h>
#include <string.h>
#include <math.h>
#define N 505
struct node{
int t,a,b,c,d;
}p[N];
struct edge{
int y,next;
}e[N*N];
int T,lk[N],used[N],n,m,first[N],top;
void add(int x,int y){
e[top].y = y;
e[top].next = first[x];
first[x] = top++;
}
int test(int x,int y){
int consume = abs(p[x].a-p[x].c)+abs(p[x].b-p[x].d);//前一个顾客的运行时间
int gap = abs(p[x].c-p[y].a)+abs(p[x].d-p[y].b);//从上一个终点到下一个起点所需的时间
return (p[y].t-p[x].t-1)>=consume+gap;
}
int dfs(int x){
int i,y;
for(i = first[x];i!=-1;i=e[i].next){
y = e[i].y;
if(!used[y]){
used[y] = 1;
if(lk[y]==-1 || dfs(lk[y])){
lk[y] = x;
return 1;
}
}
}
return 0;
}
int hungary(){
int i,res=0;
for(i = 1;i<=n;i++){
memset(used, 0, sizeof(used));
if(dfs(i))
res++;
}
return res;
}
int main(){
scanf("%d",&T);
while(T--){
int i,j,h,m;
memset(first, -1, sizeof(first));
memset(lk, -1, sizeof(lk));
top=0;
scanf("%d",&n);
for(i = 1;i<=n;i++){
scanf("%d:%d %d %d %d %d",&h,&m,&p[i].a,&p[i].b,&p[i].c,&p[i].d);
p[i].t = h*60+m;
}
for(i = 1;i<n;i++)
for(j = i+1;j<=n;j++)
if(test(i,j))
add(i,j);
printf("%d\n",n-hungary());
}
return 0;
}