hdu3656Fire station(DLX重复覆盖 + 二分)
来源:互联网 发布:720软件百科 编辑:程序博客网 时间:2024/06/07 02:15
题目请戳这里
题目大意:一个城市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重复覆盖 + 二分)
- [DLX重复覆盖] hdu 3656 Fire station
- HDU 3656 Fire station(巧妙的二分+DLX重复覆盖)
- hdu 2295 Radar(重复覆盖,二分+DLX)
- hdu2295 Radar 二分+DLX重复覆盖+A*
- HDU 2295 Radar (二分+DLX,重复覆盖)
- HDU-5046 Airport(二分+DLX重复覆盖)
- [ACM] HDU 2295 Radar (二分+DLX 重复覆盖)
- [ACM] HDU 2295 Radar (二分+DLX 重复覆盖)
- SCU2016-03 P题 二分+DLX可重复覆盖
- SCU2016-03 O题二分 + DLX可重复覆盖
- HDU 2295 Radar (DLX可重复覆盖+二分)
- HDU 5046 Airport (DLX可重复覆盖+二分)
- HDU 2295 Radar(二分+DLX重复覆盖)
- HDU 5046 Airport(二分+DLX重复覆盖)
- POJ1084-重复覆盖,DLX
- DLX 精确覆盖 重复覆盖
- HDU 3656 Fire station DLX多重覆盖
- sqlplus 远程连接 oracle 12514 错误
- linux下vi命令大全
- UVA 112 Tree Summing
- 【Java工程师之路】[1-1.6]java常用算法
- 刚学java!试着写写
- hdu3656Fire station(DLX重复覆盖 + 二分)
- virtual ABBYY2.0 Eazy
- HTTP 204 与 205 应用
- ZOJ 3422 / SOJ 3883: Go Deeper
- 妙趣横生的算法之队列的操作
- GC与显式内存管理
- 转:创业最大的悲哀是什么:尽全公司之力做了一款产品,最后却没人用!
- 数组赋值
- 10种不同类型的移动UI设计模式