给出m个客人的行程。问最少需要的出租车数量。
模型:最小路径覆盖:用最少的路径覆盖所有点(客人)
建图:如果接完上一个客人u能够来得及接下一个客人v,则u到v连一条有向边,由此得到一个DAG图。然后将每个客人拆为两个点X、Y,如果X1->X2有边,则X1->Y2连一条边,以此得到一个二分图,然后求最大匹配。
性质:最小路径覆盖数=原图顶点数-二分图最大匹配。(二分图中每有一个匹配,原图中有一条顶点不相交的边,需要的路径数减少1)。
#include<bits/stdc++.h>
using namespace std;
struct Point{
int x,y;
};
struct P{
int time;
Point s,e;
}a[505];
bool M[505][505],T[505];
int Left[505],m;
int match(int u){
for(int i=u+1;i<m;++i){
if(M[u][i]&&!T[i]){
T[i]=1;
if(!Left[i]||match(Left[i])){
Left[i]=u;
return 1;
}
}
}
return 0;
}
int Dis(Point x,Point y) {return abs(x.x-y.x)+abs(x.y-y.y);}
int main()
{
int t,i,j,Ti,Mi;
Point s,e;
cin>>t;
while(t--){
scanf("%d",&m);
for(i=0;i<m;++i){
scanf("%02d:%02d %d %d %d %d",&Ti,&Mi,&s.x,&s.y,&e.x,&e.y);
a[i].time=Ti*60+Mi;
a[i].s=s;
a[i].e=e;
}
memset(M,0,sizeof(M));
for(i=0;i<m;++i)
for(j=i+1;j<m;++j)
if(a[i].time+Dis(a[i].s,a[i].e)+Dis(a[i].e,a[j].s)+1<=a[j].time) M[i][j]=1;
int ans=0;
memset(Left,0,sizeof(Left));
for(i=0;i<m;++i){
for(j=0;j<m;++j) T[j]=0;
ans+=match(i);
}
printf("%d\n",m-ans);
}
return 0;
}