1. 程式人生 > >訓練指南 UVALive - 3126(DAG最小路徑覆蓋)

訓練指南 UVALive - 3126(DAG最小路徑覆蓋)

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最小路徑覆蓋)