UVA1201 Taxi Cab Scheme / YbtOJ「图论」第1章 二分图匹配 C. 【例题3】出租车订单 题解--zhengjun

思路

发现可以先建出一张图,每个节点表示每个订单,之间的连边 \(u\to v\) 表示同一辆出租车能否先完成 \(u\) 号订单,再去完成 \(v\) 号订单。

这样,问题转化为了在一张 dag 图上求出最小路径覆盖,见洛谷P2764题解

只需要用二分图匹配,每一次连接了一对匹配,相当于合并了两条路径(单个点也认为是路径),所以要让路径总数最小,就要让匹配的数量最大,由于是路径,所以每个点的入点和出点都最多只能连两条边。

代码

#include<bits/stdc++.h>
using namespace std;typedef long long ll;const int N=5e2+10,inf=1e9;
int T,n,p[N],head[N<<1],kk,s,t,d[N<<1],cur[N<<1];struct node{int x,y;}a[N],b[N];struct edges{int to,c,nex;}edge[N*N*2];
void add(int u,int v,int c){edge[++kk]={v,c,head[u]};head[u]=kk;edge[++kk]={u,0,head[v]};head[v]=kk;}
int dis(node x,node y){return abs(x.x-y.x)+abs(x.y-y.y);}
bool bfs(){
	queue<int>q;q.push(s);memset(d,-1,sizeof d);cur[s]=head[s];d[s]=0;while(!q.empty()){
		int u=q.front();q.pop();for(int i=head[u],v;v=edge[i].to,i;i=edge[i].nex)
			if(d[v]==-1&&edge[i].c)q.push(v),d[v]=d[u]+1,cur[v]=head[v];
	}return d[t]!=-1;
}
int dfs(int u,int lim=inf){
	if(u==t)return lim;int flow=0;for(int i=cur[u],v;v=edge[i].to,i&&flow<lim;i=edge[i].nex){
		cur[u]=i;if(d[v]!=d[u]+1||!edge[i].c)continue;int f=dfs(v,min(edge[i].c,lim-flow));
		if(!f)d[v]=-1;edge[i].c-=f;edge[i^1].c+=f;flow+=f;
	}return flow;
}
int dinic(){int maxflow=0;while(bfs())maxflow+=dfs(s);return maxflow;}
void clear(){memset(head,0,sizeof head);kk=1;}
void get(){
	scanf("%d",&n);for(int i=1,x,y;i<=n;i++)scanf("%d:%d%d%d%d%d",&x,&y,&a[i].x,&a[i].y,&b[i].x,&b[i].y),p[i]=x*60+y;
	for(int i=1;i<=n;i++)for(int j=i+1;j<=n;j++)if(dis(a[i],b[i])+dis(b[i],a[j])<p[j]-p[i])add(i,j+n,1);
	s=0;t=n+n+1;for(int i=1;i<=n;i++)add(s,i,1);for(int i=1;i<=n;i++)add(i+n,t,1);printf("%d\n",n-dinic());
}
int main(){
	for(scanf("%d",&T);T--;)clear(),get();return 0;
}
posted @ 2022-06-26 17:59  A_zjzj  阅读(9)  评论(0编辑  收藏  举报