訓練指南 UVALive - 3126(DAG最小路徑覆蓋)
阿新 • • 發佈:2019-02-05
href mat 每次 main memset problem left bbbb ini
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),要求使用最少的出租車接送乘客,使得每個顧客的要求都被執行,且每次出租車接客時需要至少提前一分鐘到達乘客所在的位置。城區是網格型的,地址用(x,y)表示,出租車從(x1,y1)到(x2,y2)需要行駛|x1 - x2| + |y1 - y2|分鐘。
題目分析:本題的模型是DAG上的最小路徑覆蓋。將每個客人視為一個節點,如果接送完顧客i後還可以繼續接送顧客j,則對應DAG中的一條邊i -> j。對每個節點拆點為i,i‘,如果圖中存在有向邊i -> j,則建邊(i,j‘)。設二分圖的最大匹配數為m,則結果即為n - m
#include<bits/stdc++.h> using namespace std; typedef long long ll; const ll mod=998244353; const int maxn=1e3+50; const ll inf=1e10; const ll INF = 1000000000; const double eps=1e-5; #define bug cout<<"bbibibibbbb="<<endl; /// 二分圖最大基數匹配 struct BPM{ int n,m; /// 左右頂點個數 int G[maxn][maxn]; /// 鄰接表 int left[maxn]; /// left[i]為右邊第i個點的匹配點編號,-1表示不存在 bool T[maxn]; /// T[i]為右邊第i個點是否已標記 int right[maxn]; /// 求最小覆蓋用 bool S[maxn]; /// 求最小覆蓋用 void init(int n,int m){ this->n=n; this->m=m; memset(G,0,sizeof(G)); } /* void AddEdge(int u,int v){ G[u].push_back(v); }*/ bool match(int u){ S[u]=true; for(int v=0;v<m;v++){ //int v=G[u][i]; if(G[u][v]&&!T[v]){ T[v]=true; if(left[v]==-1||match(left[v])){ left[v]=u; right[u]=v; return true; } } } return false; } /// 求最大匹配 int solve(){ memset(left,-1,sizeof(left)); memset(right,-1,sizeof(right)); int ans=0; for(int u=0;u<n;u++){ memset(S,0,sizeof(S)); memset(T,0,sizeof(T)); if(match(u))ans++; } return ans; } /// 求最小覆蓋。X和Y為最小覆蓋中的點集 int mincover(vector<int>& X,vector<int>& Y){ int ans=solve(); memset(S,0,sizeof(S)); memset(T,0,sizeof(T)); for(int u=0;u<n;u++) if(right[u]==-1)match(u); for(int u=0;u<n;u++) if(!S[u])X.push_back(u); for(int v=0;v<n;v++) if(T[v])Y.push_back(v); return ans; } }; BPM solver; int x1[maxn],yyy[maxn],x2[maxn],y2[maxn],t1[maxn],t2[maxn]; int dist(int a,int b,int c,int d){ return abs(a-c)+abs(b-d); } int main(){ int T; scanf("%d", &T); while(T--) { int n; scanf("%d", &n); for(int i = 0; i < n; i++) { int h, m; scanf("%d:%d%d%d%d%d", &h, &m, &x1[i], &yyy[i], &x2[i], &y2[i]); t1[i] = h*60+m; t2[i] = t1[i] + dist(x1[i], yyy[i], x2[i], y2[i]); } solver.init(n, n); for(int i = 0; i < n; i++) for(int j = i+1; j < n; j++) if(t2[i] + dist(x2[i], y2[i], x1[j], yyy[j]) < t1[j]) solver.G[i][j] = 1; // 至少要提前1分鐘到達 printf("%d\n", n - solver.solve()); } return 0; }
訓練指南 UVALive - 3126(DAG最小路徑覆蓋)