题目来源:http://acm.hdu.edu.cn/showproblem.php?pid=2295
我来补坑啦~ 没办法, 为了得到1024勋章只好
★这题就是舞蹈链求重复覆盖问题+二分法的应用,写3天,TLE3天,最后的原因竟是n和m在某个地方用反了
翻译:
有n个城市,m个雷达,现在最多可以用k个雷达,问最少将雷达的监察范围设置为多少,能监察到所有的城市
思路:
假如监察范围是r(和代码中不同),那么我们可以得到每个雷达可以监察哪些城市。
此时联想 舞蹈链求重复覆盖的模型:矩阵中选择最少的行使每一列至少有一个1
那我们接下来 可以让雷达为行、城市为列 建立十字交叉循环双向链即可 然后舞蹈链dlx.dance(0) 就可判断这个r能不能满足
如果能,那肯定往更小的找 ->这就用二分 AC 完事了~
代码
#include<iostream>
#include<algorithm>
#include<cmath>
#include<cstdio>
#include<cstring>
#include<vector>
#include<queue>
#include<stack>
#include<map>
#include<set>
#include<string>
#define ls k<<1,l,mid
#define rs k<<1|1,mid+1,r
using namespace std;
const int maxn=3000;
const int maxm=55;
const int sz=1<<10;
const int mod=1e9+7;
const int inf=2e9;
const double eps=1e-8;
const double pi=acos(-1);
typedef long long LL;
template<class t>
inline void read(t &x)
{
char c; x=1;
while((c=getchar())<'0'||c>'9') if(c=='-') x=-1;
t res=c-'0';
while((c=getchar())>='0'&&c<='9') res=res*10+c-'0';
x*=res;
}
struct DLX
{
int n,m,cnt,k;
int up[maxn],down[maxn],left[maxn],right[maxn],col[maxn];
int sz[maxm],head[maxm];
bool vis[maxm];
void init(int nn,int mm,int kk)
{
n=nn; m=mm; k=kk;
for(int i=0;i<=m;i++){
right[i]=i+1;
left[i]=i-1;
sz[i]=0;
up[i]=down[i]=i;
}
cnt=m;
right[m]=0; left[0]=m;
for(int i=1;i<=n;i++) head[i]=-1;
}
void link(int r,int c)
{
cnt++;
col[cnt]=c;
sz[c]++;
down[cnt]=c;
up[cnt]=down[c];
down[up[c]]=cnt;
up[c]=cnt;
if(head[r]==-1) head[r]=right[cnt]=left[cnt]=cnt;
else{
int tmp=head[r];
right[cnt]=tmp;
left[cnt]=left[tmp];
right[left[tmp]]=cnt;
left[tmp]=cnt;
}
}
void del(int c)
{
for(int i=down[c];i!=c;i=down[i]){
right[left[i]]=right[i];
left[right[i]]=left[i];
}
}
void resume(int c)
{
for(int i=down[c];i!=c;i=down[i]){
left[right[i]]=right[left[i]]=i;
}
}
int f()
{
int res=0;
for(int c=right[0];c!=0;c=right[c]) vis[c]=1;
for(int c=right[0];c!=0;c=right[c]){
if(vis[c]){
res++;
vis[c]=0;
for(int i=down[c];i!=c;i=down[i]){
for(int j=right[i];j!=i;j=right[j]){
vis[col[j]]=0;
}
}
}
}
return res;
}
bool dance(int dep)
{
if(dep+f()>k) return 0;
if(right[0]==0) return 1;
int now=right[0];
for(int c=now;c!=0;c=right[c]){
if(sz[c]<sz[now]) now=c;
}
for(int c=down[now];c!=now;c=down[c]){
del(c);
for(int i=right[c];i!=c;i=right[i]) del(i);
if(dance(dep+1)) return 1;
for(int i=right[c];i!=c;i=right[i]) resume(i);
resume(c);
}
return 0;
}
}dlx;
struct point
{
double x,y;
}radar[maxm],city[maxm];
double get(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 n,m,k,t;
read(t);
while(t--){
read(n); read(m); read(k);
for(int i=1;i<=n;i++){
read(city[i].x); read(city[i].y);
}
for(int i=1;i<=m;i++){
read(radar[i].x); read(radar[i].y);
}
double l=0,r=2000;
while(r-l>=eps){
double mid=(l+r)/2;
dlx.init(m,n,k);
for(int i=1;i<=m;i++){
for(int j=1;j<=n;j++){
if(mid>=get(radar[i],city[j])){
dlx.link(i,j);
}
}
}
if(dlx.dance(0)) r=mid-eps;
else l=mid+eps;
}
printf("%.6lf\n",l);
}
return 0;
}