匈牙利演算法

本文最後更新於:2022年11月19日 中午

開幾個array:
1. now -> 記錄該點目前被誰佔有
2. mark -> 記錄該點是否被嘗試過

範例

// Author : ysh
// 10/21/2022 Fri 16:06:37.82
// https://tioj.ck.tp.edu.tw/problems/1069
#include<bits/stdc++.h>
using namespace std;
struct box{
    int t,x,y;
    box(int t = 0,int x = 0,int y = 0):
        t(t), x(x), y(y) {};
    inline bool operator<(const box &a) const {
        return t > a.t;
    }
};
inline int dt(int a,int b,int c,int d) {
    return (abs(a - c) + abs(b - d));
}
int check(int n,vector<box>&f) {
    vector<vector<int>>v(n);
    vector<bool>mark;
    vector<int>now(n,-1);
    function<bool(int)> ck = [&] (int x) {
        for(int &i : v.at(x)) {
            if(mark.at(i)) continue;
            mark.at(i) = 1;
            if(now.at(i) != -1) {
                if(!ck(now.at(i))) {
                    continue;
                }
            }
            now.at(i) = x;
            return 1;
        }
        return 0;
    };
    for(int i = 0;i<n;i++) {
        for(int j = 0;j<n;j++) {
            if(i == j) continue;
            if(f[i].t < f[j].t && f.at(i).t + dt(f.at(i).x,f.at(i).y,f.at(j).x,f.at(j).y) <= f.at(j).t) {
                v.at(i).push_back(j);
            }
        }
    }
    int ans = 0;
    for(int i = 0;i<n;i++) {
        mark = vector<bool>(n);
        if(ck(i)) ans++;
    }
    return n - ans;
}
int main() {
    ios::sync_with_stdio(false);
    cin.tie(0);

    int n;cin>>n;
    while(n--) {
        int m;cin>>m;
        vector<box>f(m);
        for(auto &i : f) {
            cin>>i.t>>i.x>>i.y;
        }
        // sort(f.rbegin(),f.rend());
        cout<<check(m,f)<<"\n";
    }
    return 0;
}

做法

對於每一個點,記錄它能在時間內到達的其他點,存在v[]裡,接著對於每個點,我們可以發現,如果在時間內無法到達任何點,或是能到達的點都被佔領了,就需要多一位人員。

所以我們寫一個函數,嘗試為傳入的點匹配一個能到達的點,如果成功就回傳true,失敗則測試能否為已匹配的點找到其他可行的點,若都失敗,則回傳false。注意如果對於一個點,被多次呼叫(該次呼叫前就已經匹配過)時,就需要再為它匹配另一個點。

最後,我們只需要對於每個點呼叫一次函數,如果回傳false,代表無法匹配,所以將需要人數加一。


匈牙利演算法
http://mysh212.github.io/algosolution/匈牙利演算法/
作者
ysh
發布於
2022年11月16日
更新於
2022年11月19日
許可協議