首页 > 代码库 > [ACM] HDU 2295 Radar (二分+DLX 重复覆盖)
[ACM] HDU 2295 Radar (二分+DLX 重复覆盖)
Radar
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 2593 Accepted Submission(s): 1012
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
1 3 3 2 3 4 3 1 5 4 1 1 2 2 3 3
2.236068
解题思路:
题意为有m个雷达,每个雷达的覆盖范围都为以r为半径的圆,给定他们的坐标,有n个城市,给定他们的坐标,求最小的r,使得每个城市都被雷达覆盖,限制条件为最多只有k个雷达工作。
二分答案r,判断所需要的雷达数是否小于给定的k,找到最小的r。
用Dlx重复覆盖来判断。首先建图:m行,n列的矩形,也就是横坐标代表雷达,纵坐标代表城市,如果雷达与城市之间的距离小于等于当前的r,则坐标处标记为1,否则为0,这样就转化为了01矩阵,也就是解决问题能不能在这个矩阵中找出一些行(行数小于等于k),使得这些行组成的新矩阵,每列都至少有一个1(重复覆盖,每列可以有多个1).
关于精确覆盖和重复覆盖,下面转载于: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 重复覆盖)