Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 2593 Accepted Submission(s): 1012
1 3 3 2 3 4 3 1 5 4 1 1 2 2 3 3
2.236068
解题思路:
题意为有m个雷达,每个雷达的覆盖范围都为以r为半径的圆,给定他们的坐标,有n个城市,给定他们的坐标,求最小的r,使得每个城市都被雷达覆盖,限制条件为最多只有k个雷达工作。
二分答案r,判断所需要的雷达数是否小于给定的k,找到最小的r。
用Dlx重复覆盖来判断。首先建图:m行,n列的矩形,也就是横坐标代表雷达,纵坐标代表城市,如果雷达与城市之间的距离小于等于当前的r,则坐标处标记为1,否则为0,这样就转化为了01矩阵,也就是解决问题能不能在这个矩阵中找出一些行(行数小于等于k),使得这些行组成的新矩阵,每列都至少有一个1(重复覆盖,每列可以有多个1).
关于精确覆盖和重复覆盖,下面转载于:http://www.cnblogs.com/jh818012/p/3252154.html
精确覆盖:
首先选择当前要覆盖的列(含1最少的列),将该列和能够覆盖到该列的行全部去掉,再枚举添加的方法。
枚举某一行r,假设它是解集中的一个,那么该行所能覆盖到的所有列都不必再搜,所以删除该行覆盖到的所有列,又由于去掉的列相当于有解,所以能够覆盖到这些列的行也不用再搜,删之。
重复覆盖:
首先选择当前要覆盖的列(同上),将该列删除,枚举覆盖到该列的所有行:对于某一行r,假设它是解集中的一个,那么该行所能覆盖到的列都不必再搜,所以删除该行覆盖到的所有列。
注意此时不用删去覆盖到这些列的行,因为一列中允许有多个1。
这里有一个A*的优化:估价函数h意义为从当前状态最好情况下需要添加几条边才能覆盖。
代码:
#include <stdio.h>
#include <string.h>
#include <iostream>
#include <algorithm>
#include <vector>
#include <queue>
#include <set>
#include <map>
#include <string>
#include <math.h>
#include <stdlib.h>
#include <time.h>
using namespace std;
const int maxn=52;
const int maxm=52;
const int maxnode=3020;
int n,m,k;
struct DLX
{
int n,m,size;
int U[maxnode],D[maxnode],R[maxnode],L[maxnode],Row[maxnode],Col[maxnode];
int H[maxn],S[maxn];
int ansd,ans[maxn];
void init(int _n,int _m)
{
n=_n;
m=_m;
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;
}
bool v[maxnode];
int f()//精确覆盖区估算剪枝
{
int ret=0;
for(int c=R[0];c!=0;c=R[c])
v[c]=true;
for(int c=R[0];c!=0;c=R[c])
if(v[c])
{
ret++;
v[c]=false;
for(int i=D[c];i!=c;i=D[i])
for(int j=R[i];j!=i;j=R[j])
v[Col[j]]=false;
}
return ret;
}
bool dance(int d)
{
if(d+f()>k)
return false;
if(d>k)
return false;
if(R[0]==0)
return true;
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;
}
};
DLX g;
const double eps=1e-8;
struct point
{
double x,y;
}city[maxm],radar[maxn];
double dis(point a,point b)
{
return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y));
}
int main()
{
int t;
scanf("%d",&t);
while(t--)
{
scanf("%d%d%d",&m,&n,&k);
for(int i=1;i<=m;i++)
scanf("%lf%lf",&city[i].x,&city[i].y);
for(int i=1;i<=n;i++)
scanf("%lf%lf",&radar[i].x,&radar[i].y);
double l=0,r=1e5;
while(r-l>=eps)
{
double mid=(l+r)/2.0;
g.init(n,m);
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
if(dis(radar[i],city[j])<mid-eps)
g.link(i,j);
if(g.dance(0))
r=mid-eps;
else
l=mid+eps;
}
printf("%.6lf\n",l);
}
return 0;
}
[ACM] HDU 2295 Radar (二分+DLX 重复覆盖)
原文:http://blog.csdn.net/sr_19930829/article/details/39853743