hdu3656Fire station(DLX重复覆盖 + 二分)
题目大意:一个城市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重复覆盖 + 二分)的更多相关文章
- hdu 2295 dlx重复覆盖+二分答案
题目大意: 有一堆雷达工作站,安放至多k个人在这些工作站中,找到一个最小的雷达监控半径可以使k个工作人所在的雷达工作站覆盖所有城市 二分半径的答案,每次利用dlx的重复覆盖来判断这个答案是否正确 #i ...
- (中等) HDU 2295 , DLX+重复覆盖+二分。
Description N cities of the Java Kingdom need to be covered by radars for being in a state of war. S ...
- hdu2295(重复覆盖+二分)
题目连接:http://acm.hdu.edu.cn/showproblem.php?pid=2295 题意::一个国家有n个城市,有m个地方可以建造雷达,最多可以建K个雷达(K>=1 & ...
- hdu5046(重复覆盖+二分)
题目连接:http://acm.hdu.edu.cn/showproblem.php?pid=5046 题意:要在n个城市里建造不超过k个机场覆盖所有城市,问机场城市之间最大距离最小为多少. 分析:二 ...
- [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 ...
- HDU 5046 Airport【DLX重复覆盖】
题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=5046 题意: 给定n个城市的坐标,要在城市中建k个飞机场,使城市距离最近的飞机场的最长距离最小,求这 ...
- HDU5046 Airport dancing links 重复覆盖+二分
这一道题和HDU2295是一样 是一个dancing links重复覆盖解决最小支配集的问题 在给定长度下求一个最小支配集,只要小于k就行 然后就是二分答案,每次求最小支配集 只不过HDU2295是浮 ...
- HDU 2295.Radar (DLX重复覆盖)
2分答案+DLX判断可行 不使用的估计函数的可重复覆盖的搜索树将十分庞大 #include <iostream> #include <cstring> #include < ...
- (中等) HDU 3335 , DLX+重复覆盖。
Description As we know,the fzu AekdyCoin is famous of math,especially in the field of number theory. ...
随机推荐
- 模板-->Guass消元法(求解多元一次方程组)
如果有相应的OJ题目,欢迎同学们提供相应的链接 相关链接 所有模板的快速链接 简单的测试 None 代码模板 /* * TIME COMPLEXITY:O(n^3) * PARAMS: * a The ...
- 【算法】最长公共子序列(nlogn)
转载注明出处:http://blog.csdn.net/wdq347/article/details/9001005 (修正了一些错误,并自己重写了代码) 最长公共子序列(LCS)最常见的算法是时间复 ...
- Python之路,Day15 - Django适当进阶篇
Python之路,Day15 - Django适当进阶篇 本节内容 学员管理系统练习 Django ORM操作进阶 用户认证 Django练习小项目:学员管理系统设计开发 带着项目需求学习是最有趣 ...
- jQuery创建ajax关键词数据搜索
在web开发过程当中,我们经常需要在前台页面输入关键词进行数据的搜索,我们通常使用的搜索方式是将搜索结果用另一个页面显示,这样的方式对于搭建高性能网站来说不是最合适的,今天给大家分享一下如何使用 jQ ...
- 【转】HttpServlet详解
[转]HttpServlet详解 Servlet的框架是由两个Java包组成:javax.servlet和javax.servlet.http. 在javax.servlet包中定义了所有的Servl ...
- strace 使用
- php小知识点
1.字符串可以里面的字符可以像数组一样访问,比如$s = "123";$s[1]就等于2,如果字符串为中文则会乱码,需要使用mb_substr进行截取: 2.php中的单引号(' ...
- How to scroll the window using JQuery $.scrollTo() function
$('html, body').animate({scrollTop: $("#page").offset().top}, 2000); http://stackoverflow. ...
- 利用GDB在远程开发机进行调试
由于一些环境的制约,很多同学都可能需要在开发机上进行调试,但由于开发机资源的限制,在开发机上直接进行本地的GDB环境配置就成了难题,这个时候其实我们可以利用GDB中自带的gdbserver工具就可以进 ...
- phpcms首页调用会员头像及金钱、积分等信息,并按照积分点数排列
<div class="box"> <h5>最新会员</h5> <div class="col-auto">&l ...