[ACM] HDU 2295 Radar (二分+DLX 重复覆盖)
来源:互联网 发布:网络剧制作播出许可证 编辑:程序博客网 时间:2024/06/01 07:36
Radar
Each of the last M lines consists of the coordinate of a radar station.
All coordinates are separated by one space.
Technical Specification
1. 1 ≤ T ≤ 20
2. 1 ≤ N, M ≤ 50
3. 1 ≤ K ≤ M
4. 0 ≤ X, Y ≤ 1000
13 3 23 43 15 41 12 23 3
2.236068
解题思路:
题意为有m个雷达,每个雷达的覆盖范围都为以r为半径的圆,给定他们的坐标,有n个城市,给定他们的坐标,求最小的r,使得每个城市都被雷达覆盖,限制条件为最多只有k个雷达工作。
二分答案r,判断所需要的雷达数是否小于给定的k,找到最小的r。
用Dlx重复覆盖来判断。首先建图:m行,n列的矩形,也就是横坐标代表雷达,纵坐标代表城市,如果雷达与城市之间的距离小于等于当前的r,则坐标处标记为1,否则为0,这样就转化为了01矩阵,也就是解决问题能不能在这个矩阵中找出一些行(行数小于等于k),使得这些行组成的新矩阵,每列都至少有一个1(重复覆盖,每列可以有多个1).
注意maxnode的范围 ,最大不能只是 n*m, 列头结点还得加上 即 n*m+m
关于精确覆盖和重复覆盖,下面转载于: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 重复覆盖)
- [ACM] HDU 2295 Radar (二分+DLX 重复覆盖)
- hdu 2295 Radar(重复覆盖,二分+DLX)
- HDU 2295 Radar (二分+DLX,重复覆盖)
- HDU 2295 Radar (DLX可重复覆盖+二分)
- HDU 2295 Radar(二分+DLX重复覆盖)
- HDU 2295 Radar(重复覆盖,DLX)
- HDU 2295 Radar DLX重复覆盖
- HDU 2295 Radar DLX重复覆盖
- HDU 2295 Radar(DLX可重复覆盖)
- HDU 2295 Radar(二分+重复覆盖)
- hdu2295 Radar 二分+DLX重复覆盖+A*
- HDU 2295 Radar(二分加DLX)
- HDU 2295 Radar (DLX求重复覆盖, A*搜索)
- 【HDU】2295 Radar 二分+重复覆盖
- HDU 5046 Airport (DLX可重复覆盖+二分)
- HDU 5046 Airport(二分+DLX重复覆盖)
- HDU-5046 Airport(二分+DLX重复覆盖)
- Android 分享一个流量显示界面
- UITableViewCell 的巧妙复用
- 黑马程序员——Java的保留关键字
- C#安装部署打包SQLSERVER数据库
- 冒泡排序,选择排序
- [ACM] HDU 2295 Radar (二分+DLX 重复覆盖)
- Android 网络请求方式
- 迷宫问题DFS
- Linux上安装Mahout的方法步骤
- 优先队列详解(转载)
- Adnroid 通过HttpURLConnection模拟post表单提交
- 我的vim使用心得
- C++九月学习感悟
- {dede:field.content/}{dede:field.body/}区别