题目请戳这里

题目大意:一个城市n个点,现在要建m个消防站,消防站建在给定的n个点中。求建m个消防站后,m个消防站要覆盖所有的n个点的覆盖半径最小。

题目分析:重复覆盖问题,DLX解决。不过要求覆盖半径最小,需要二分。虽然给的范围并不大,DLX毕竟还是暴力搜索,而且精度有6位小数,因此直接二分距离的话会TLE!解决方案是将图中任意2点的距离记录下来,去重后二分已知的距离。因为消防站建在给定的n个点中,那么最小覆盖半径一定在任意2点距离中产生。

DLX搜索的时候,一般习惯删除的时候从左往右,不过效率却不一定高。比如这题,从左向右删除和从右向左删除,跑的时间至少差了1s以上!可见用dancing links搜索的时候姿势还是很重要的。有时候换个姿势也许效率更高~

详情请见代码:

#include <iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
using namespace std;
const int N = 51;
const int M = 30001;
const double eps = 1e-7; double dis[N][N];
double tle[M];
int s[M],h[M],u[M],d[M],l[M],r[M],col[M],row[M];
int point[N][2];
int m,n,num,len;
int fs;
double getdis(int i,int j)
{
return sqrt((double)(point[i][0] - point[j][0])*(point[i][0] - point[j][0])
+(double)(point[i][1] - point[j][1])*(point[i][1] - point[j][1]));
}
void read()
{
scanf("%d%d",&n,&m);
int i,j;
len = 1;
tle[len ++] = 0;
for(i = 1;i <= n;i ++)
{
dis[i][i] = 0.0;
scanf("%d%d",&point[i][0],&point[i][1]);
for(j = 1;j < i;j ++)
dis[i][j] = dis[j][i] = getdis(i,j),tle[len ++] = dis[i][j];
}
}
void init()
{
memset(h,0,sizeof(h));
memset(s,0,sizeof(s));
for(int i = 0;i <= n;i ++)
{
u[i] = d[i] = i;
l[i] = (i + n) % (n + 1);
r[i] = (i + 1) % (n + 1);
}
num = n + 1;
}
void add(int i,int j)
{
if(h[i])
{
r[num] = h[i];
l[num] = l[h[i]];
r[l[num]] = l[r[num]] = num;
}
else
h[i] = l[num] = r[num] = num;
s[j] ++;
u[num] = u[j];
d[num] = j;
d[u[num]] = num;
u[j] = num;
col[num] = j;
row[num] = i;
num ++;
}
void build(double md)
{
int i,j;
init();
for(i = 1;i <= n;i ++)
for(j = 1;j <= n;j ++)
if(md - dis[i][j] > -eps)
add(i,j);
}
void remove(int c)
{
for(int i = d[c];i != c;i = d[i])
l[r[i]] = l[i],r[l[i]] = r[i],s[col[i]] --;
}
void resume(int c)
{
for(int i = u[c];i != c;i = u[i])
l[r[i]] = r[l[i]] = i,s[col[i]] ++;
}
int A()
{
int i,j,k,ret = 0;
bool vis[N];
memset(vis,false,sizeof(vis));
for(i = l[0];i;i = l[i])
{
if(vis[i] == false)
{
vis[i] = true;
ret ++;
for(j = d[i];j != i;j = d[j])
for(k = r[j];k != j;k = r[k])
vis[col[k]] = true;
}
}
return ret;
}
void dfs(int k)
{
if(k + A() >= fs)
return;
int i,j;
if(!r[0])
{
fs = min(fs,k);
return;
}
int mn = 1000000;
int c;
for(i = l[0];i;i = l[i])
{
if(mn > s[i])
{
mn = s[i];
c = i;
}
}
for(i = d[c];i != c;i = d[i])
{
remove(i);
for(j = l[i];j != i;j = l[j])
{
remove(j);
}
dfs(k + 1);
for(j = r[i];j != i;j = r[j])
{
resume(j);
}
resume(i);
}
}
void solve()
{
int la,ra,mid,ans;
sort(tle + 1,tle + len);
int i = len;
int j;
len = 2;
for(j = 2;j < i;j ++)
if(fabs(tle[j] - tle[j - 1]) > eps)
tle[len ++] = tle[j];
len --;
la = 1;ra = len;
while(la <= ra)
{
mid = (la + ra)>>1;
build(tle[mid]);
fs = M;
dfs(0);
if(fs <= m)
{
ans = mid;
ra = mid - 1;
}
else
la = mid + 1;
}
printf("%f\n",tle[ans]);
}
int main()
{
int _;
scanf("%d",&_);
while(_ --)
{
read();
solve();
}
return 0;
}
//1953MS 636K

hdu3656Fire station(DLX重复覆盖 + 二分)的更多相关文章

  1. hdu 2295 dlx重复覆盖+二分答案

    题目大意: 有一堆雷达工作站,安放至多k个人在这些工作站中,找到一个最小的雷达监控半径可以使k个工作人所在的雷达工作站覆盖所有城市 二分半径的答案,每次利用dlx的重复覆盖来判断这个答案是否正确 #i ...

  2. (中等) HDU 2295 , DLX+重复覆盖+二分。

    Description N cities of the Java Kingdom need to be covered by radars for being in a state of war. S ...

  3. hdu2295(重复覆盖+二分)

    题目连接:http://acm.hdu.edu.cn/showproblem.php?pid=2295 题意::一个国家有n个城市,有m个地方可以建造雷达,最多可以建K个雷达(K>=1 & ...

  4. hdu5046(重复覆盖+二分)

    题目连接:http://acm.hdu.edu.cn/showproblem.php?pid=5046 题意:要在n个城市里建造不超过k个机场覆盖所有城市,问机场城市之间最大距离最小为多少. 分析:二 ...

  5. [ACM] HDU 2295 Radar (二分法+DLX 重复覆盖)

    Radar Problem Description N cities of the Java Kingdom need to be covered by radars for being in a s ...

  6. HDU 5046 Airport【DLX重复覆盖】

    题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=5046 题意: 给定n个城市的坐标,要在城市中建k个飞机场,使城市距离最近的飞机场的最长距离最小,求这 ...

  7. HDU5046 Airport dancing links 重复覆盖+二分

    这一道题和HDU2295是一样 是一个dancing links重复覆盖解决最小支配集的问题 在给定长度下求一个最小支配集,只要小于k就行 然后就是二分答案,每次求最小支配集 只不过HDU2295是浮 ...

  8. HDU 2295.Radar (DLX重复覆盖)

    2分答案+DLX判断可行 不使用的估计函数的可重复覆盖的搜索树将十分庞大 #include <iostream> #include <cstring> #include < ...

  9. (中等) HDU 3335 , DLX+重复覆盖。

    Description As we know,the fzu AekdyCoin is famous of math,especially in the field of number theory. ...

随机推荐

  1. AS 进行单元测试

    以下为本人在AndroidStudio 2.0 上实测后得出的结论,不像网上那一堆堆的误人子弟的文章,都是过时的或者根本就是不对的. 简介 和eclipse需要配置清单文件不同,AndroidStud ...

  2. Android 中Webview 自适应屏幕

    随笔 - 478  文章 - 3  评论 - 113 Android 中Webview 自适应屏幕   webview中右下角的缩放按钮能不能去掉 settings.setDisplayZoomCon ...

  3. CSS入门学习(转)

    一.基础学习 1.何为CSS CSS是Cascading Style Sheets(层叠样式表)的简称,是一种标记语言,它不需要编译,可以直接由浏览器执行(属于浏览器解释型语 言). CSS文件也可以 ...

  4. lucene查询排序结果原理总结

    参考文章 Lucene3.0结果排序原理+操作+示例 Lucene的排序算法 一句话总结lucene排序算法是什么样的 关键几个概念 参考文档: http://lucene.apache.org/co ...

  5. (转)PHP函数spl_autoload_register()用法和__autoload()介绍

      转--http://www.jb51.net/article/29624.htm 又是框架冲突导致__autoload()失效,用spl_autoload_register()重构一下,问题解决 ...

  6. [置顶] VS自带工具:dumpbin的使用

    有时候我们想查看一个exe引用了哪些动态库,或者我们想看某个动态库包含哪些接口函数,这个时候可以使用dumpbin.exe工具: 1.输入Dumpbin -imports calldll.exe查看它 ...

  7. iOS 使用xmpp做聊天客户端

    可以号称史上最详细的xmpp做iOS客户端聊天介绍. 简介:XMPP协议是一种基于Socket长连接.以XML格式进行基本信息交换.C/S  S/S多种架构的聊天协议 XMPPServer 基于XMP ...

  8. 什么是NSAssert?

    断言, 判断是否符合某个特定条件, 符合就继续运行程序, 反之就抛出异常, 后面为自定义错误提示, 也可以使用NSParameterAssert, 在调试上有着很大的方便 int a = 0; NSA ...

  9. [JS] save txt file

    (function () { var blob = new Blob(['content'], {type: 'text/plain; charset=utf-8'}), blobUrl = URL. ...

  10. zookeeper集群一次性启动

    编写shell脚本 新建文本,命名为start-zookeeper.sh #!/bin/sh echo "start zkServer…" for i in master work ...