0w1

HR Bike Racers ( Binary Search + Maximum Matching )

https://www.hackerrank.com/challenges/bike-racers
參考了這篇:用于二分图匹配的匈牙利算法 | Comzyh的博客
第一次寫二分圖最大匹配,原來沒有想像中那麼難。我想二分圖最大匹配基本上可以想成是求婚問題,一群男士和一群女士有一些關聯,這些關聯可以用邊描述(要嘛相互能接受,要嘛相互不能接受),這時候要替他們匹配,使得最多組相互能接受的男女配對產生(當然不允許同一個人存在於多組的情形)。
為什麼是說求婚問題呢,想像是匹配的一邊是男生,另一邊是女生,且規定男生要主動追求女生。按編號每一個男生挑選理想的女生,如果該女生還沒有追求者,就形成配對,結束。否則試著踢開該女生的男士,接著讓被踢開的男士遞迴著找當前有沒有可配對的女生,有的話就各自配對,返回,如此就又多一對了。每一個男士挑選完後,將是最大匹配。
這個問題只要會最大匹配就很顯然了,二分時間,構圖判斷最大匹配是否滿足 K。

#include <bits/stdc++.h>
using namespace std;

typedef long long ll;
typedef pair< int, int > pii;
typedef vector< int > vi;
typedef vector< vi > vvi;
typedef vector< pii > vpii;
typedef vector< char > vch;

const int MOD7 = 1e9 + 7;
const int INF = 0x3f3f3f3f;

// #define MULTIPLE_CASES

struct Hungarian{
    vvi G;
    vi bf;
    int girl_size;
    vi vis;

    Hungarian( const vvi &_G, const int gs ): G( _G ), girl_size( gs ){
        bf.resize( girl_size );
        vis.resize( girl_size );
        fill( bf.begin(), bf.end(), -1 );
    }

    bool foundMate( int u, const vvi &G ){
        for( int v : G[ u ] ){ // u: boy, v: girl
            if( vis[ v ] ) continue;
            vis[ v ] = 1;
            if( bf[ v ] == -1 || foundMate( bf[ v ], G ) )
                return ( bf[ v ] = u ) or true;
        }
        return false;
    }

    int maxMatch(){
        int res = 0;
        for( int i = 0; i < G.size(); ++i ){
            fill( vis.begin(), vis.end(), 0 );
            if( foundMate( i, G ) ) ++res;
        }
        return res;
    }
};

ll eulerDisSqr( const pii &p1, const pii &p2 ){
    ll dx = p1.first - p2.first;
    ll dy = p1.second - p2.second;
    return dx * dx + dy * dy;
}

bool ok( ll x, int gol, const vpii &player_pos, const vpii &bike_pos ){
    vvi G( player_pos.size() );
    for( int i = 0; i < player_pos.size(); ++i )
        for( int j = 0; j < bike_pos.size(); ++j )
            if( eulerDisSqr( player_pos[ i ], bike_pos[ j ] ) <= x )
                G[ i ].push_back( j );
    Hungarian hung( G, bike_pos.size() );
    return hung.maxMatch() >= gol;
}

void solve(){
    int N, M, K; cin >> N >> M >> K;
    vpii player_pos( N ), bike_pos( M );
    for( int i = 0; i < N; ++i )
        cin >> player_pos[ i ].first >> player_pos[ i ].second;
    for( int i = 0; i < M; ++i )
        cin >> bike_pos[ i ].first >> bike_pos[ i ].second;
    ll lb = 0, rb = 1e16;
    ll ans = -1;
    while( lb <= rb ){
        ll mid = ( lb + rb ) / 2;
        if( ok( mid, K, player_pos, bike_pos ) ) ans = mid, rb = mid - 1;
        else lb = mid + 1;
    }
    cout << ans << "\n";
}

int main(){
    ios::sync_with_stdio( false );
    cin.tie( 0 );
    cout.tie( 0 );

    #ifdef MULTIPLE_CASES
        int T; cin >> T; while( T-- ) solve();
    #endif

    #ifndef MULTIPLE_CASES
        solve();
    #endif

    return 0;
}