以下转自 这里 :
最小支配集问题:二分枚举最小距离,判断可行性。可行性即重复覆盖模型,DLX解之。
A*的启发函数:
对当前矩阵来说,选择一个未被控制的列,很明显该列最少需要1个行来控制,所以ans++。
该列被控制后,把它所对应的行,全部设为已经选择,并把这些行对应的列也设为被控制。继续选择未被控制的列,直到没有这样的列。
#include <cstdio> #include <cstring> #include <cstdlib> #include <cmath> #include <algorithm> using namespace std; const double eps = 1e-9; const int INF = 1 << 30; const int MAXN = 60; struct Point { double x, y; Point( double x = 0, double y = 0 ):x(x), y(y) { } void readPoint() { scanf( "%lf%lf", &x, &y ); return; } }; Point city[MAXN]; Point radar[MAXN]; int N, M, K; int L[MAXN*MAXN], R[MAXN*MAXN]; int U[MAXN*MAXN], D[MAXN*MAXN]; int C[MAXN*MAXN], cnt[MAXN]; bool mx[MAXN][MAXN]; bool vis[MAXN]; int head; void Remove( int c ) { for ( int i = D[c]; i != c; i = D[i] ) { R[ L[i] ] = R[i]; L[ R[i] ] = L[i]; } return; } void Resume( int c ) { for ( int i = D[c]; i != c; i = D[i] ) { R[ L[i] ] = i; L[ R[i] ] = i; } return; } //估价函数:至少还需要选择几个雷达 int h() { memset( vis, false, sizeof(vis) ); int res = 0; for ( int c = R[head]; c != head; c = R[c] ) { if ( !vis[c] ) { ++res; for ( int i = D[c]; i != c; i = D[i] ) for ( int j = R[i]; j != i; j = R[j] ) vis[ C[j] ] = true; } } return res; } bool DFS( int dep ) { if ( R[head] == head ) return true; if ( dep + h() > K ) return false; int minv = INF, c; for ( int i = R[head]; i != head; i = R[i] ) { if ( cnt[i] < minv ) { minv = cnt[i]; c = i; } } for ( int i = D[c]; i != c; i = D[i] ) { Remove(i); for ( int j = R[i]; j != i; j = R[j] ) { Remove(j); --cnt[ C[j] ]; } if ( DFS( dep + 1 ) ) return true; for ( int j = R[i]; j != i; j = R[j] ) { Resume(j); ++cnt[ C[j] ]; } Resume(i); } return false; } bool build() { head = 0; for ( int i = 0; i < N; ++i ) { R[i] = i + 1; L[i + 1] = i; } R[N] = 0; L[0] = N; //列链表 for ( int j = 1; j <= N; ++j ) { int pre = j; cnt[j] = 0; for ( int i = 1; i <= M; ++i ) { if ( mx[i][j] ) { ++cnt[j]; int cur = i * N + j; D[pre] = cur; U[cur] = pre; C[cur] = j; pre = cur; } } U[j] = pre; D[pre] = j; if ( !cnt[j] ) return false; } for ( int i = 1; i <= M; ++i ) { int pre = -1; int first = -1; for ( int j = 1; j <= N; ++j ) { if ( mx[i][j] ) { int cur = i * N + j; if ( pre == -1 ) first = cur; else { R[pre] = cur; L[cur] = pre; } pre = cur; } } if ( first != -1 ) { L[first] = pre; R[pre] = first; } } return true; } /*************以上DLX模板***************/ double PointDis( Point a, Point b ) { return sqrt( (a.x - b.x)*(a.x - b.x) + (a.y - b.y)*(a.y - b.y) ); } int dcmp( double x ) //控制精度 { if ( fabs(x) < eps ) return 0; else return x < 0 ? -1 : 1; } bool check( double mid ) { memset( mx, false, sizeof(mx) ); for ( int i = 1; i <= M; ++i ) for ( int j = 1; j <= N; ++j ) { if ( dcmp( PointDis( radar[i], city[j] ) - mid ) < 0 ) mx[i][j] = true; } if ( build() ) return DFS(0); return false; } double solved() { double l = 0.0; double r = 1500.0; double ans; while ( dcmp( r - l ) > 0 ) { double mid = (l + r) / 2.0; if ( check( mid ) ) { r = mid; ans = mid; } else l = mid; } return ans; } int main() { int T; scanf( "%d", &T ); while ( T-- ) { scanf( "%d%d%d", &N, &M, &K ); for( int i = 1; i <= N; ++i ) city[i].readPoint(); for ( int i = 1; i <= M; ++i ) radar[i].readPoint(); printf( "%.6f ", solved() ); } return 0; }