有N个城市,M个雷达站,K个操作员,从M个雷达站中选择K个,来覆盖所有的N城市,每个雷达有相同的覆盖半径,问:最小的覆盖半径是多少
最小支配集问题,最小支配集属于NP难题,找不到多项式解法,所有只能搜索,但是普通的搜索是过不了的,鉴于这种类型的题,可以用一种的特殊的结构–双向链表,于是就可以用DLX来优化这个搜索.
可以先二分距离,然后用DLX判断就行了。
import java.io.BufferedInputStream;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.io.StreamTokenizer;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.NavigableSet;
import java.util.PriorityQueue;
import java.util.Queue;
import java.util.Scanner;
import java.util.Set;
import java.util.SortedSet;
import java.util.Stack;
import java.util.StringTokenizer;
import java.util.TreeSet;
import org.omg.CORBA.Object;
public class Main {
public static void main(String[] args) throws IOException{
StreamTokenizer cin = new StreamTokenizer(new BufferedInputStream(System.in));
InputReader in = new InputReader(System.in) ;
PrintWriter out = new PrintWriter(System.out) ;
int t = in.nextInt() ;
for(int i = 1 ; i <= t ; i++){
new Task().solve(in, out) ; //out.flush() ;
}
out.flush() ;
}
}
class Task{
static final double eps = 1e-8 ;
static final int N = 62 ;
static double[] dx = new double[N] ;
static double[] dy = new double[N] ;
static double[] px = new double[N] ;
static double[] py = new double[N] ;
static double[][] dist = new double[N][N] ;
ArrayList<Double> radiu = new ArrayList<Double>() ;
int n , m , k ;
public void solve(InputReader in , PrintWriter out) throws IOException{
n = in.nextInt() ;
m = in.nextInt() ;
k = in.nextInt() ;
for(int i = 1 ; i <= n ; i++){
dx[i] = in.nextDouble() ;
dy[i] = in.nextDouble() ;
}
for(int i = 1 ; i <= m ; i++){
px[i] = in.nextDouble() ;
py[i] = in.nextDouble() ;
}
for(int i = 1 ; i <= m ; i++){
for(int j = 1 ; j <= n ; j++){
dist[i][j] = Math.pow(px[i] - dx[j] , 2.0) + Math.pow(py[i] - dy[j] , 2.0) ;
radiu.add(dist[i][j]) ;
}
}
Collections.sort(radiu) ;
out.printf("%.6f" , Math.sqrt(bs()));
out.println();
}
boolean ok(double d){
DLX dlx = new DLX(m , n , k) ;
for(int i = 1 ; i <= m ; i++){
for(int j = 1 ; j <= n ; j++){
if(dist[i][j] - eps < d){
dlx.Link(i , j) ;
}
}
}
return dlx.Dance(0) ;
}
double bs(){
int l = 0 , r = radiu.size() - 1 , mid , s = 0 ;
while(l <= r){
mid = (l + r) >> 1 ;
if(ok(radiu.get(mid))){
s = mid ;
r = mid - 1 ;
}
else l = mid + 1 ;
}
return radiu.get(s) ;
}
}
class DLX{
static final int maxnode = 4000;
static final int MaxM = 70;
static final int MaxN = 70;
static int[] U = new int[maxnode];
static int[] R = new int[maxnode];
static int[] L = new int[maxnode];
static int[] D = new int[maxnode];
static int[] Row = new int[maxnode];
static int[] Col = new int[maxnode];
static int[] H = new int[MaxN] ;
static int[] S = new int[MaxM] ;
static boolean[] vis = new boolean[maxnode] ;
int limit ;
int n , m , size ;
DLX(int n , int m , int limit){
this.n = n;
this.m = m;
this.limit = limit ;
for(int i = 0 ; i <= m ; i++){
S[i] = 0;
U[i] = D[i] = i;
L[i] = i-1;
R[i] = i+1;
}
R[m] = 0; L[0] = m;
size = m;
for(int i = 1 ; i <= n ; i++)
H[i] = -1;
}
void Link(int r,int c){
++S[Col[++size]=c];
Row[size] = r;
D[size] = D[c];
U[D[c]] = size;
U[size] = c;
D[c] = size;
if(H[r] < 0) H[r] = L[size] = R[size] = size;
else{
R[size] = R[H[r]];
L[R[H[r]]] = size;
L[size] = H[r];
R[H[r]] = size;
}
}
void remove(int c){
for(int i = D[c];i != c;i = D[i]){
L[R[i]] = L[i];
R[L[i]] = R[i];
}
}
void resume(int c){
for(int i = U[c] ; i != c ; i = U[i])
L[R[i]] = R[L[i]] = i;
}
int f(){
int ret = 0;
for(int c = R[0];c != 0;c = R[c]) vis[c] = true;
for(int c = R[0];c != 0;c = R[c]){
if(vis[c]){
ret++;
vis[c] = false;
for(int i = D[c];i != c;i = D[i]){
for(int j = R[i];j != i;j = R[j])
vis[Col[j]] = false;
}
}
}
return ret;
}
boolean Dance(int d){
if(d + f() > limit) return false;
if(R[0] == 0) return d <= limit;
int c = R[0] ;
for(int i = R[0] ; i != 0 ; i = R[i]){
if(S[i] < S[c]) 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);
if(Dance(d+1))return true;
for(int j = L[i] ; j != i ; j = L[j]) resume(j);
resume(i);
}
return false;
}
}
class InputReader{
public BufferedReader reader;
public StringTokenizer tokenizer;
public InputReader(InputStream stream){
reader = new BufferedReader(new InputStreamReader(stream), 32768) ;
tokenizer = null ;
}
public String next(){
while(tokenizer == null || ! tokenizer.hasMoreTokens()){
try{
tokenizer = new StringTokenizer(reader.readLine());
}catch (IOException e) {
throw new RuntimeException(e);
}
}
return tokenizer.nextToken();
}
public int nextInt(){
return Integer.parseInt(next());
}
public long nextLong(){
return Long.parseLong(next());
}
public double nextDouble(){
return Double.parseDouble(next());
}
}