http://acm.hdu.edu.cn/showproblem.php?pid=229
题意:
一个国家有n个城市,m个雷达,我们同时操作的雷达数最多为k,给出城市与国家的坐标,求小于等于k的操作下,雷达覆盖的能够覆盖所有城市的最小覆盖半径。
思路:
城市作为列,雷达作为行,二分枚举雷达的半径+DLX重复覆盖求解。
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
#include <cstdio> #include <cstring> #include <iostream> #include <cmath> using namespace std; // freopen("data.in","r",stdin); #define CL(a,num) memset((a),(num),sizeof(a)) #define inf 0x7f7f7f7f #define M 55 #define N 55 #define maxn 3317 const double eps = 1e-8; const int head = 0; struct node{ double x,y; }city[N],rar[M]; int u[maxn],d[maxn],l[maxn],r[maxn],c[maxn],row[maxn]; int s[N]; bool hash[M]; int n,m,k; int size; int dblcmp(double x){ if (x > eps) return 1; else if (x < -eps) return -1; else return 0; } bool isok(int a,int b,double R){ double x = rar[a].x - city[b].x; double y = rar[a].y - city[b].y; double s = x*x + y*y; if (dblcmp(R - s) >= 0) return true; else return false; } void init(){ int i; for (i = 1; i <= n; ++i){ l[i] = i - 1; r[i] = i + 1; u[i] = d[i] = i; c[i] = i; s[i] = 0; } l[head] = n; r[head] = 1; r[n] = head; size = n + 1; } void build(int R){ int i,j; for (i = 1; i <= m; ++i){//枚举行 int rh = -1; for (j = 1; j <= n; ++j){//枚举列 if (isok(i,j,R)){//满足条件即可以覆盖 int x = j; c[size] = x; row[size] = i; s[x]++; u[size] = u[x]; d[u[x]] = size; u[x] = size; d[size] = x; if (rh == -1){ l[size] = r[size] = size; rh = size; } else{ l[size] = l[rh]; r[l[rh]] = size; l[rh] = size; r[size] = rh; } size++; } } } } void remove(int ci){ int i; for (i = d[ci]; i != ci; i = d[i]){ l[r[i]] = l[i]; r[l[i]] = r[i]; } } void resume(int ci){ int i; for (i = u[ci]; i != ci; i = u[i]){ l[r[i]] = r[l[i]] = i; } } int h(){ int i,j; int res = 0; CL(hash,false); for (i = r[head]; i != head; i = r[i]){ if (!hash[i]){ res++; hash[i] = true; for (j = d[i]; j != i; j = d[j]){ for (int k = r[j]; k != j; k = r[k]){ hash[c[k]] = true; } } } } return res; } bool dfs(int dep){ int i,j; if (dep + h() > k) return false; if (r[head] == head) return true; int MIN = inf, ci = 0; for (i = r[head]; i != head; i = r[i]){ if (s[i] < MIN){ MIN = s[i]; ci = i; } } for (i = d[ci]; i != ci; i = d[i]){ remove(i); for (j = r[i]; j != i; j = r[j]){ remove(j); } if (dfs(dep + 1)) return true; for (j = l[i]; j != i; j = l[j]){ resume(j); } resume(i); } return false; } int main(){ // freopen("din.txt","r",stdin); int i,j; int T; scanf("%d",&T); while (T--){ scanf("%d%d%d",&n,&m,&k); for (i = 1; i <= n; ++i) scanf("%lf%lf",&city[i].x,&city[i].y); for (j = 1; j <= m; ++j) scanf("%lf%lf",&rar[j].x,&rar[j].y); double L = 0, R = 50000.0; double ans = 0; while (dblcmp(R - L) > 0){ double mid = (R + L)/2.0; init(); build(mid*mid);//这里不知道为啥这么坑爹,我开方求不对。 if (dfs(0)){ ans = mid; R = mid; } else L = mid; } printf("%.6lf\n",ans); } return 0; }