大白例题P356 你在一座城市里负责一个大型活动的接待工作。你需要去送m个人从出发地到目的地,已知每个人的出发时间出发地点,和目的地点,你的任务是用尽量少的出租车送他们,使得每次出租车接客人,至少能提前一分钟达到他所在的位置,城市为网格 (x1,y1) ===>(x2,y2) 需要|x1-x2|+|y1-y2|分钟
题解:
本题的模型是DAG的最小路径覆盖。所谓最小路径覆盖就是在图中找尽量少的路径,使得每个结点恰好在一条路径上(话句话说,不同路径不能有公共点)。单独的节点也可以作为一条路径。
本题中“时间” 是一个天然的序, 因此可以构图如下: 每个客人是一个节点,如果同一个出租车在接完客人u以后来得及接客人v,离岸边u_>v, 不难发现是一个DAG, 并且它的最小 路径覆盖就是本题的答案。
大白书 P357讲解:DAG最小路径覆盖的解法把所有节点i 拆成 X 节点i 和Y 节点i‘ , 如果图G中存在有向边 i->j,则在二分图中引入i->j‘, 设最大匹配数位m,则结果就是 n-m.
1 #include <iostream> 2 #include <algorithm> 3 #include <string.h> 4 #include <vector> 5 #include <cstdio> 6 using namespace std; 7 const int maxn =505; 8 struct person{ 9 int time; 10 int sx,sy,tx,ty; 11 }P[maxn]; 12 struct BPM{ 13 int n,m; 14 int left[maxn],right[maxn]; 15 bool S[maxn],T[maxn]; 16 vector<int>G[maxn]; 17 void init(int n, int m){ 18 this->n = n; 19 this->m = m; 20 for(int i=0; i<m; i++) G[i].clear(); 21 } 22 void add_edg(int u, int v){ 23 G[u].push_back(v); 24 } 25 bool match(int u){ 26 S[u] =true; 27 for(int i =0; i<(int )G[u].size(); i++){ 28 int v = G[u][i]; 29 if(T[v] == false){ 30 T[v]=true; 31 if(left[v]==-1 || match(left[v])){ 32 left[v]=u; right[u]=v; 33 return true; 34 } 35 } 36 } 37 return false; 38 } 39 int solve(){ 40 memset(left,-1,sizeof(left)); 41 memset(right,-1,sizeof(right)); 42 int ans=0; 43 for(int u =0; u<n; u++){ 44 memset(S,false,sizeof(S)); 45 memset(T,false,sizeof(T)); 46 if(match(u)) ans++; 47 } 48 return ans; 49 } 50 }solver; 51 int main() 52 { 53 int cas; 54 scanf("%d",&cas); 55 for(int cc =1; cc<=cas; ++cc){ 56 int m; 57 scanf("%d",&m); 58 for(int i=0; i<m; i++){ 59 int th,tm; 60 scanf("%d:%d%d%d%d%d",&th,&tm,&P[i].sx,&P[i].sy,&P[i].tx,&P[i].ty); 61 P[i].time = th*60+tm; 62 } 63 solver.init(m,m); 64 for(int i=0; i<m; i++){ 65 int a1 = abs(P[i].sx-P[i].tx)+abs(P[i].sy-P[i].ty); 66 for(int j=0; j<m; j++){ 67 int a2 = abs(P[i].tx-P[j].sx)+abs(P[i].ty-P[j].sy); 68 if( (P[i].time+a1+a2) < P[j].time ){ 69 solver.add_edg(i,j); 70 } 71 } 72 } 73 printf("%d\n",m-solver.solve()); 74 } 75 return 0; 76 }
时间: 2024-10-12 21:29:17