CFR 513 F. Scaygerboss ( Flow, Binary Search )
題意:
有個 N * M 棋盤,有些格子是障礙。
有一個怪盜,以及 Males 個男生,Females 個女生。
這些人都會用 r, c, t 表示座標位置以及移動一單位距離所需要的時間。
問至少要多少時間,才能使每個人都恰好和一位異性在同一個格子上。
怪盜可以選擇要成為男性或者女性。
制約:
1 ≤ N, M ≤ 22
解法:
對所有人求出對所有格子的最短路徑。
二分搜答案,每次重新建圖。
模型很顯然,詳見代碼。
#include <bits/stdc++.h> using namespace std; template< class T > struct Dinic { static const int MAXV = 20000; static constexpr T INF = 1e9; struct Edge { int v; T f; int re; Edge( int _v, T _f, int _re ): v( _v ), f( _f ), re( _re ) {} }; int n, s, t, level[ MAXV ]; vector< Edge > E[ MAXV ]; int now[ MAXV ]; Dinic( int _n, int _s, int _t ): n( _n ), s( _s ), t( _t ) {} void add_edge( int u, int v, T f ) { E[ u ].emplace_back( v, f, E[ v ].size() ); E[ v ].emplace_back( u, 0, E[ u ].size() - 1 ); } bool BFS() { memset( level, -1, sizeof( level ) ); queue< int > que; que.emplace( s ); level[ s ] = 0; while( not que.empty() ) { int u = que.front(); que.pop(); for( auto it: E[ u ] ) { if( it.f > 0 and level[ it.v ] == -1 ) { level[ it.v ] = level[ u ] + 1; que.emplace( it.v ); } } } return level[ t ] != -1; } T DFS( int u, T nf ) { if( u == t ) return nf; T res = 0; while( now[ u ] < E[ u ].size() ) { Edge &it = E[ u ][ now[ u ] ]; if( it.f > 0 and level[ it.v ] == level[ u ] + 1 ) { T tf = DFS( it.v, min( nf, it.f ) ); res += tf; nf -= tf; it.f -= tf; E[ it.v ][ it.re ].f += tf; if( nf == 0 ) return res; } else ++now[ u ]; } if( not res ) level[ u ] = -1; return res; } T flow( T res = 0 ) { while( BFS() ) { T temp; memset( now, 0, sizeof( now ) ); while( temp = DFS( s, INF ) ) { res += temp; res = min( res, INF ); } } return res; } }; const int MAXN = 22; const int MAXM = 22; int N, M, Males, Females; string G[ MAXN ]; int R[ MAXN * MAXM * 2 + 1 ], C[ MAXN * MAXM * 2 + 1 ], T[ MAXN * MAXM * 2 + 1 ]; long long dp[ MAXN * MAXM * 2 + 1 ][ MAXN ][ MAXM ]; signed main() { ios::sync_with_stdio( false ); { cin >> N >> M >> Males >> Females; for( int i = 0; i < N; ++i ) { cin >> G[ i ]; } if( Males + 1 == Females ) { ++Males; } else if( Females + 1 == Males ) { cin >> R[ Males + Females ] >> C[ Males + Females ] >> T[ Males + Females ]; --R[ Males + Females ], --C[ Males + Females ]; } else { cout << -1 << endl; exit( 0 ); } for( int i = 0; i < Males; ++i ) { cin >> R[ i ] >> C[ i ] >> T[ i ]; --R[ i ], --C[ i ]; } for( int i = 0; i < Females; ++i ) { cin >> R[ Males + i ] >> C[ Males + i ] >> T[ Males + i ]; --R[ Males + i ], --C[ Males + i ]; } if( T[ Males + Females ] ) { ++Females; } } { memset( dp, 0x3f, sizeof( dp ) ); priority_queue< tuple< long long, int, int, int > > pq; for( int i = 0; i < Males + Females; ++i ) { pq.emplace( dp[ i ][ R[ i ] ][ C[ i ] ] = 0LL, i, R[ i ], C[ i ] ); } while( not pq.empty() ) { long long dis; int who, x, y; tie( dis, who, x, y ) = pq.top(); pq.pop(); dis *= -1; if( dp[ who ][ x ][ y ] != dis ) continue; for( int di = 0; di < 4; ++di ) { const static int dx[] = { 0, 1, 0, -1 }; const static int dy[] = { 1, 0, -1, 0 }; int nx = x + dx[ di ]; int ny = y + dy[ di ]; if( not ( 0 <= nx and nx < N and 0 <= ny and ny < M ) ) continue; if( G[ nx ][ ny ] == '#' ) continue; if( dp[ who ][ nx ][ ny ] > dis + T[ who ] ) { pq.emplace( -( dp[ who ][ nx ][ ny ] = dis + T[ who ] ), who, nx, ny ); } } } } { long long lb = -1, ub = 1e12; while( lb + 1 != ub ) { long long mid = lb + ub >> 1; int SRC = 2 * N * M + Males + Females, DST = SRC + 1; Dinic< int > din( DST + 1, SRC, DST ); for( int i = 0; i < Males; ++i ) { din.add_edge( SRC, 2 * N * M + i, 1 ); for( int x = 0; x < N; ++x ) { for( int y = 0; y < M; ++y ) { if( mid < dp[ i ][ x ][ y ] ) continue; din.add_edge( 2 * N * M + i, x * M + y, 1 ); } } } for( int x = 0; x < N; ++x ) { for( int y = 0; y < M; ++y ) { din.add_edge( x * M + y, N * M + x * M + y, 1 ); } } for( int i = 0; i < Females; ++i ) { for( int x = 0; x < N; ++x ) { for( int y = 0; y < M; ++y ) { if( mid < dp[ Males + i ][ x ][ y ] ) continue; din.add_edge( N * M + x * M + y, 2 * N * M + Males + i, 1 ); } } din.add_edge( 2 * N * M + Males + i, DST, 1 ); } ( din.flow() == Males ? ub : lb ) = mid; } cout << ( ub == 1e12 ? -1 : ub ) << endl; } return 0; }