题意
给定m个客人的出发时间和起点,终点,问最少用几个出租车可以完成任务,出租车需要在出发前一分钟到达起点。坐标(x,y),时间花费|x1-x2|+|y1-y2|。
0 < M < 500,出发时间00:00 to 23:59
题解
如果在送完一个客人之后还能够去送另一个客人,肯定是最好的。所以把一个客人拆成两个点:在起点和在终点,如果在终点的点能够再去送在起点的点就连边,最后ans=n-最大匹配数,因为每增加一个匹配就可以少用一辆出租车。
把时间全部弄成分钟制会好处理一点。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include<cstdio> #include<vector> #include<cstring> #include<cmath> #include <algorithm> using namespace std; const int maxn=1005; int t,n; int timer,vis[maxn],match[maxn]; vector<int> e[maxn]; struct point{ int h; int x,y; }a[maxn]; void init(){ timer=0; memset(vis,0,sizeof(vis)); memset(match,0,sizeof(match)); for(int i=1;i<=n;i++) e[i].clear(); } void get(int i){ int h,m,x,y,xx,yy; scanf("%d:%d%d%d%d%d",&h,&m,&x,&y,&xx,&yy); h=h*60+m; a[i]=(point){h,x,y}; h+=abs(x-xx)+abs(y-yy); a[i+n]=(point){h,xx,yy}; } bool check(point a,point b){ return a.h+abs(a.x-b.x)+abs(a.y-b.y)<b.h; } void make_edge(){ for(int i=n+1;i<=2*n;i++) for(int j=n;j;j--){ if(!check(a[i],a[j])) continue; e[j].push_back(i); } } bool dfs(int u){ if(vis[u]==timer) return false; vis[u]=timer; for(unsigned int i=0;i<e[u].size();i++){ int v=e[u][i]; if(!match[v]||dfs(match[v])){ match[v]=u; return true; } } return false; } int main(){ scanf("%d",&t); while(t--){ scanf("%d",&n); init(); for(int i=1;i<=n;i++) get(i); make_edge(); int ans=0; for(int i=1;i<=n;i++){ timer++; if(dfs(i)) ans++; } printf("%d ",n-ans); } }