题目链接:
http://acm.hdu.edu.cn/showproblem.php?pid=2295
题意:给出一些城市及一些雷达的坐标,要求从这些雷达中选取最多k个能够覆盖所有的城市,问雷达的最小覆盖半径为多少。
二分半径,则可转化为一个判定问题,即给定雷达的覆盖半径,问从这些雷达中最多选取k个,是否能够覆盖所有这些城市。、
这里用到了Dancing Links 解决重复覆盖问题的方法来进行判断,与精确覆盖问题的不同之处在于,Remove中只删除当前列,而不是把所有与之相关的行及列全部删去,用
Resume恢复即可,另,由于种类型题目的限制,Dancing Links的效率不高,需要在搜索中加上启发式判断,于是就有了另一个函数的 h() 设计,使效率大为提高。
Code:
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
typedef struct{
double x,y;
}Point;
#define M 64
const int head=0;
const int V=M*M;
const double eps=1e-7;
int R[V],L[V],U[V],D[V],C[V];
int S[V],H[V],size;
int n,m;
int Limit;
Point radar[M];
Point city[M];
double Dis2(Point p,Point q)
{
p.x-=q.x;p.y-=q.y;
return p.x*p.x+p.y*p.y;
}
void Remove(int c)
{
int i;//只删除该列
for(i=D[c];i!=c;i=D[i])
L[R[i]]=L[i],R[L[i]]=R[i];
}
void Resume(int c)
{
int i;
for(i=U[c];i!=c;i=U[i])
L[R[i]]=R[L[i]]=i;
}
int h()
{
int r=0,i,j,k;
int hash[M];
memset(hash,0,sizeof(hash));
for(i=R[head];i!=head;i=R[i]){
if(!hash[i]){
r++;
hash[i]=1;
for(j=D[i];j!=i;j=D[j]){
for(k=R[j];k!=j;k=R[k])
hash[C[k]]=1;
}
}
}
return r;
}
int Dance(int k)
{
int i,j,min,c;
if(k+h()>Limit) return 0;
if(R[head]==head)return 1;
for(i=R[head],c=0,min=M;i!=head;i=R[i]){
if(S[i]<min) min=S[i],c=i;
}
for(i=D[c];i!=c;i=D[i]){
Remove(i);
for(j=R[i];j!=i;j=R[j])
Remove(j);
if(Dance(k+1)) return 1;
for(j=L[i];j!=i;j=L[j])
Resume(j);
Resume(i);
}
return 0;
}
void Link(int &r,int c)
{
S[c]++;C[size]=c;
U[size]=U[c];D[U[c]]=size;
D[size]=c;U[c]=size;
if(r==-1)
L[size]=R[size]=r=size;
else{
L[size]=L[r];R[L[r]]=size;
R[size]=r;L[r]=size;
}size++;
}
int Solve(double rr)
{
int i,j;
for(i=0;i<=n;i++){
S[i]=0;U[i]=D[i]=i;
R[i]=i+1;L[i+1]=i;
}R[n]=0;
size=n+1;
memset(H,-1,sizeof(H));
for(i=0;i<m;i++){
for(j=0;j<n;j++){
if(Dis2(radar[i],city[j])<=rr)
Link(H[i],j+1);
}
}
for(i=1;i<=n;i++){
if(S[i]==0)
return 0;
}
return Dance(0);
}
int main()
{
int t,i;
double up,low,mid;
scanf("%d",&t);
while(t--){
scanf("%d%d%d",&n,&m,&Limit);
for(i=0;i<n;i++)
scanf("%lf%lf",&city[i].x,&city[i].y);
for(i=0;i<m;i++)
scanf("%lf%lf",&radar[i].x,&radar[i].y);
low=0.000001;up=1416.0;
while(low+eps<up){
mid=(low+up)*0.5;
if(Solve(mid*mid))
up=mid;
else low=mid;
}
printf("%lf\n",up);
}
return 0;
}