【LA3126 训练指南】出租车 【DAG最小路径覆盖】

题意

你在一座城市里负责一个大型活动的接待工作。明天将有m位客人从城市的不同的位置出发,到达他们各自的目的地。已知每个人的出发时间,出发地点和目的地。你的任务是用尽量少的出租车送他们,使得每次出租车接客人时,至少能提前一分钟到达他所在的位置。注意,为了满足这一条件,要么这位客人是这辆出租车接送的第一个人,要么在接送完上一个客人后,有足够的时间从上一个目的地开到这里。

为了简单起见,假定城区是网格型的,地址用坐标(x,y)表示,出租车从(x1,y1)到(x2,y2)处需要行驶|x1-x2|+|y1-y2|分钟。

分析

这个模型叫做DAG的最小路径覆盖。所谓最小路径覆盖,就是在图中找尽量少的路径,使得每个结点恰好在一条路径上(换句话说,不同的路径不能有公共点)。注意,单独的一个结点也可以作为一条路径。

DAG最小路径覆盖的解法如下:把所有的结点i拆为X结点i和Y结点i‘,如果图G中存在有向边i->j,则二分图中引入边i->j‘。设二分图的最大匹配数为m,则结果就是n-m。因为匹配和路径覆盖是一一对应的。对于路径覆盖中的每条简单路径,除了最后一个“结尾结点”以外都有唯一的后继和他对应(既匹配结点),因此匹配数就是非结尾结点的个数,当匹配数达到最大时,此时,结尾结点的个数最少,既路径条数最少。

本题建模:每个客人是一个结点,如果同一个出租车接完客人u以后还来得及接客人v,连边u->v。不难发现,这个图是一个DAG,并且它的最小路径覆盖就是本题的答案。

  1 #include <cstdio>
  2 #include <cstring>
  3 #include <iostream>
  4 #include <algorithm>
  5 #include <queue>
  6 #include <cmath>
  7
  8 using namespace std;
  9 const int maxn=3000+10;
 10 const int maxm=800000;
 11 const int INF=2147483600;
 12 struct Dinic{
 13     int head[maxn],Next[maxm],to[maxm],cap[maxm],flow[maxm];
 14     int sz,n,m,s,t;
 15     bool vis[maxn];
 16     int cur[maxn],d[maxn];
 17     void init(int n){
 18         this->n=n;
 19         memset(head,-1,sizeof(head));
 20         this->sz=-1;
 21     }
 22     void add_edge(int a,int b,int c){
 23         ++sz;
 24         to[sz]=b;
 25         cap[sz]=c;flow[sz]=0;
 26         Next[sz]=head[a];head[a]=sz;
 27         ++sz;
 28         to[sz]=a;
 29         cap[sz]=c;flow[sz]=c;
 30         Next[sz]=head[b];head[b]=sz;
 31     }
 32     bool BFS(){
 33         memset(vis,0,sizeof(vis));
 34         queue<int>Q;
 35         vis[s]=1;
 36         d[s]=0;
 37         Q.push(s);
 38         while(!Q.empty()){
 39             int u=Q.front();Q.pop();
 40             for(int i=head[u];i!=-1;i=Next[i]){
 41                 int v=to[i];
 42                 if(!vis[v]&&cap[i]>flow[i]){
 43                     vis[v]=1;
 44                     d[v]=d[u]+1;
 45                     Q.push(v);
 46                 }
 47             }
 48         }
 49         return vis[t];
 50    }
 51     int DFS(int x,int a){
 52         if(x==t||a==0)return a;
 53         int Flow=0,f;
 54         for(int& i=cur[x];i!=-1;i=Next[i]){
 55             int v=to[i];
 56             if(d[v]==d[x]+1&&(f=DFS(v,min(a,cap[i]-flow[i])))>0){
 57                 Flow+=f;
 58                 flow[i]+=f;
 59                 flow[i^1]-=f;
 60                 a-=f;
 61                 if(a==0)break;
 62             }
 63         }
 64         return Flow;
 65     }
 66     int Maxflow(int s,int t){
 67         this->s=s,this->t=t;
 68         int Flow=0;
 69         while(BFS()){
 70             for(int i=0;i<=n;i++)
 71              cur[i]=head[i];
 72
 73             Flow+=DFS(s,INF);
 74         }
 75         return Flow;
 76     }
 77 }dinic;
 78 int T,m;
 79 int sth[maxn],stm[maxn],sx[maxn],sy[maxn],enx[maxn],eny[maxn];
 80 int dist(int x1,int y1,int x2,int y2){
 81     return abs(x1-x2)+abs(y1-y2);
 82 }
 83 void pass_time(int hou,int mi,int &Hou,int &Mi,int tim){
 84     Mi=mi+tim;
 85     Hou=hou+Mi/60;
 86     Mi=Mi%60;
 87     return;
 88 }
 89 int main(){
 90     scanf("%d",&T);
 91     for(int t=1;t<=T;t++){
 92         scanf("%d",&m);
 93         dinic.init(2*m+5);
 94         for(int i=1;i<=m;i++){
 95             scanf("%d:%d%d%d%d%d",&sth[i],&stm[i],&sx[i],&sy[i],&enx[i],&eny[i]);
 96         }
 97
 98         for(int i=1;i<=m;i++){
 99             for(int j=1;j<=m;j++){
100                 int tim=dist(sx[i],sy[i],enx[i],eny[i])+dist(enx[i],eny[i],sx[j],sy[j]);
101                 int Enh,Enm;
102                 pass_time(sth[i],stm[i],Enh,Enm,tim);
103                 if(Enh*60+Enm>=sth[j]*60+stm[j])continue;
104                 dinic.add_edge(i,j+m,1);
105             }
106         }
107         for(int i=1;i<=m;i++)
108           dinic.add_edge(0,i,1);
109         for(int i=1;i<=m;i++)
110           dinic.add_edge(i+m,2*m+1,1);
111         int ans=dinic.Maxflow(0,2*m+1);
112         printf("%d\n",m-ans);
113
114     }
115 return 0;
116 }

原文地址:https://www.cnblogs.com/LQLlulu/p/9307511.html

时间: 2024-11-06 07:11:41

【LA3126 训练指南】出租车 【DAG最小路径覆盖】的相关文章

训练指南 UVALive - 3126(DAG最小路径覆盖)

layout: post title: 训练指南 UVALive - 3126(DAG最小路径覆盖) author: "luowentaoaa" catalog: true mathjax: true tags: - 二分图 - 图论 - 训练指南 - 最小路径覆盖 Taxi Cab Scheme UVALive - 3126 题目大意:n个客人,从城市的不同位置出发,到达他们的目的地.已知每个人的出发时间hh:mm,出发地点(x1,y1)及目的地(x2,y2),要求使用最少的出租车接

uva1201 DAG 最小路径覆盖,转化为 二分图

大白例题P356 你在一座城市里负责一个大型活动的接待工作.你需要去送m个人从出发地到目的地,已知每个人的出发时间出发地点,和目的地点,你的任务是用尽量少的出租车送他们,使得每次出租车接客人,至少能提前一分钟达到他所在的位置,城市为网格 (x1,y1) ===>(x2,y2) 需要|x1-x2|+|y1-y2|分钟 题解: 本题的模型是DAG的最小路径覆盖.所谓最小路径覆盖就是在图中找尽量少的路径,使得每个结点恰好在一条路径上(话句话说,不同路径不能有公共点).单独的节点也可以作为一条路径. 本

POJ 1422 DAG最小路径覆盖

求无向图中能覆盖每个点的最小覆盖数 单独的点也算一条路径 这个还是可以扯到最大匹配数来,原因跟上面的最大独立集一样,如果某个二分图(注意不是DAG上的)的边是最大匹配边,那说明只要取两个端点只要一条边即可. 故最小覆盖数还是 顶点数-最大匹配数 根据DAG建图的时候,就是DAG有边就给对应的端点建边 #include <iostream> #include <cstdio> #include <cstring> using namespace std; int d[15

POWOJ 1739: 魔术球问题 DAG最小路径覆盖转最大流

1739: 魔术球问题 题意: 假设有n根柱子,现要按下述规则在这n根柱子中依次放入编号为1,2,3,...的球. (1)每次只能在某根柱子的最上面放球. (2)在同一根柱子中,任何2个相邻球的编号之和为完全平方数. 试设计一个算法,计算出在n根柱子上最多能放多少个球.对于给定的n,计算在n根柱子上最多能放多少个球. tags: 对大佬来说应该是很素的一道题,但某还是花了好多时间才做出来.. 一开始连建图都有点懵,然后最小路径还是新概念,最大匹配也不太懂,最大流倒是会一点. 然后要打印答案,也不

POJ1422 Air Raid 【DAG最小路径覆盖】

Air Raid Time Limit: 1000MS   Memory Limit: 10000K Total Submissions: 6763   Accepted: 4034 Description Consider a town where all the streets are one-way and each street leads from one intersection to another. It is also known that starting from an i

bzoj 2044 三维导弹拦截——DAG最小路径覆盖(二分图)

题目:https://www.lydsy.com/JudgeOnline/problem.php?id=2044 还以为是CDQ.发现自己不会三维以上的-- 第一问可以n^2.然后是求最长不下降子序列吗?dilworth好像不能用吧. 那就是能从自己转移到哪些状态就从自己向哪些状态连边,然后就是最小路径覆盖了.用二分图的 n-最大匹配 . 注意:没有位置的限制所以可以先按 x 排序! #include<iostream> #include<cstdio> #include<c

poj 2060 Taxi Cab Scheme(DAG图的最小路径覆盖)

题意: 出租车公司有M个订单. 订单格式:     hh:mm  a  b  c  d 含义:在hh:mm这个时刻客人将从(a,b)这个位置出发,他(她)要去(c,d)这个位置. 规定1:从(a,b)到(c,d)所花的时间为:abs(a-c)+abs(b-d). 规定2:一辆出租车如果要接单,必须在客人出发前1分钟(包括)以前接单. 问,最少派出多少辆出租车,可以完成所有任务. 思路: 把每一笔单看成一个点,如果完成第i个单后可以接到第j个单,则 i->j连上线. 则题为:求这个DAG图的最小路

有向无环图(DAG)的最小路径覆盖

DAG的最小路径覆盖 定义:在一个有向图中,找出最少的路径,使得这些路径经过了所有的点. 最小路径覆盖分为最小不相交路径覆盖和最小可相交路径覆盖. 最小不相交路径覆盖:每一条路径经过的顶点各不相同.如图,其最小路径覆盖数为3.即1->3>4,2,5. 最小可相交路径覆盖:每一条路径经过的顶点可以相同.如果其最小路径覆盖数为2.即1->3->4,2->3>5. 特别的,每个点自己也可以称为是路径覆盖,只不过路径的长度是0. DAG的最小不相交路径覆盖 算法:把原图的每个点

POJ 1442 Air Raid(DAG图的最小路径覆盖)

题意: 有一个城镇,它的所有街道都是单行(即有向)的,并且每条街道都是和两个路口相连.同时已知街道不会形成回路. 可以在任意一个路口放置一个伞兵,这个伞兵会顺着街道走,依次经过若干个路口. 问最少需要投放几个伞兵,使得每个路口都被伞兵拜访过.并且要满足每个路口只能被一个伞兵拜访过. 思路: 裸DAG图的最小路径覆盖. DAG图的最小路径覆盖数 = 节点数 - 二分图最大匹配 代码: vector<int> graph[125]; int cx[125],cy[125]; bool bmask[