HDU 2295 Radar 重复覆盖 DLX

题意:

  N个城市,M个雷达站,K个操作员,问雷达的半径至少为多大,才能覆盖所有城市。M个雷达中最多只能有K个同时工作。

思路:

  二分雷达的半径,看每个雷达可以覆盖哪些城市,然后做重复覆盖,判断这个半径是否可行。

  我是直接二分的半径,跑了300+ms,看了Virtual Judge上面跑得快的代码,才发现为了不浪费半径的长度,最小的半径一定等于某一个雷达站到某一个城市之间的距离。这样一来枚举量就小了很多,只需要15ms……

代码:

  300+ms的 -_-

  1 #include <iostream>
  2 #include <cstdio>
  3 #include <cstring>
  4 #include <cstdlib>
  5 #include <cmath>
  6 #include <algorithm>
  7 #include <string>
  8 #include <queue>
  9 #include <stack>
 10 #include <vector>
 11 #include <map>
 12 #include <set>
 13 #include <functional>
 14 #include <cctype>
 15 #include <time.h>
 16 
 17 using namespace std;
 18 
 19 const double eps = 1e-8;
 20 const int INF = 1<<30;
 21 const int MAXN = 55;
 22 const int MAXR = 55;
 23 const int MAXNODE = MAXN*MAXR;
 24 
 25 struct DLX {
 26 // 行编号从1开始,列编号为1~n,结点0是表头结点;结点1~n是各列顶部的虚拟结点
 27     int n, sz; // 列数,结点总数
 28     int S[MAXN]; //各列结点数
 29 
 30     int row[MAXNODE], col[MAXNODE]; //各结点行列编号
 31     int L[MAXNODE], R[MAXNODE], U[MAXNODE], D[MAXNODE]; //十字链表
 32 
 33     int ansd, ans[MAXR]; //
 34 
 35     void init(int n)  { //n是列数
 36         this->n = n;
 37 
 38         //虚拟结点
 39         for (int i = 0; i <= n; i++) {
 40             U[i] = i; D[i] = i; L[i] = i-1; R[i] = i+1;
 41         }
 42         R[n] = 0; L[0] = n;
 43         sz = n+1;
 44         memset(S, 0, sizeof(S));
 45     }
 46 
 47     void addRow(int r, vector<int> columns) {
 48         //这一行的第一个结点
 49         //行没有设头结点,每一行连成一个环形
 50         int first = sz;
 51         for (int i = 0; i < columns.size(); i++) {
 52             int c = columns[i];
 53             L[sz] = sz-1; R[sz] = sz+1; D[sz] = c; U[sz] = U[c];
 54             D[U[c]] = sz; U[c] = sz;
 55             row[sz] = r; col[sz] = c;
 56             S[c]++; sz++;
 57         }
 58         R[sz-1] = first; L[first] = sz-1;
 59     }
 60 
 61     //顺着链表A,遍历s外的其他元素
 62     #define FOR(i, A, s) for (int i = A[s]; i != s; i = A[i])
 63 
 64     void remove(int c) { //删除c列
 65         FOR(i, D, c) {
 66             L[R[i]] = L[i]; R[L[i]] = R[i];
 67         }
 68     }
 69 
 70     void restore(int c) { //回连c列
 71         FOR(i, U, c) {
 72             L[R[i]] = R[L[i]] = i;
 73         }
 74     }
 75 
 76     bool vis[MAXN];
 77 
 78     int f() {
 79         int ret = 0;
 80         FOR(c, R, 0) vis[c] = true;
 81         FOR(c, R, 0) if (vis[c]) {
 82             ret++; vis[c] = false;
 83             FOR(i, D, c) FOR(j, R, i)
 84                 vis[col[j]] = false;
 85         }
 86         return ret;
 87     }
 88 
 89     void dfs(int d) { //d为递归深度
 90         if (d+f()>=ansd) return ;
 91         if (R[0] == 0) { //找到解
 92             ansd = min(ansd, d); //记录解的长度
 93             return ;
 94         }
 95 
 96         //找S最小的C列
 97         int c = R[0]; //第一个未删除的列
 98         for (int i = R[0]; i != 0; i = R[i]) if (S[i]<S[c]) c = i;
 99 
100         for (int i = D[c]; i != c; i = D[i]) { //用结点i所在的行覆盖第c列
101             remove(i);
102             for (int j = R[i]; j != i; j = R[j]) remove(j); //删除节结点i所在行覆盖第c列
103             ans[d] = row[i];
104             dfs(d+1);
105             for (int j = L[i]; j != i; j = L[j]) restore(j); // 恢复
106             restore(i);
107         }
108     }
109 
110     int solve() {
111         ansd = INF;
112         dfs(0);
113         return ansd;
114     }
115 };
116 
117 DLX solver;
118 vector<int> columns;
119 
120 int n, m, k;
121 double a[MAXN][2];
122 double b[MAXN][2];
123 double G[MAXN][MAXN];
124 
125 int check(double x) {
126     solver.init(n);
127     for (int i = 0; i < m; i++) {
128         columns.clear();
129         for (int j = 0; j < n; j++) if (G[i][j]<=x)
130             columns.push_back(j+1);
131         if (!columns.empty()) solver.addRow(i+1, columns);
132     }
133     return solver.solve();
134 }
135 
136 int main() {
137     #ifdef Phantom01
138         freopen("HDU2295.txt", "r", stdin);
139     #endif //Phantom01
140 
141     int T;
142     scanf("%d", &T);
143     while (T--) {
144         scanf("%d%d%d", &n, &m, &k);
145         for (int i = 0; i < n; i++)
146             scanf("%lf%lf", &a[i][0], &a[i][1]);
147         for (int i = 0; i < m; i++)
148             scanf("%lf%lf", &b[i][0], &b[i][1]);
149         double l = 0, r = 0, mm;
150         for (int i = 0; i < m; i++) {
151             for (int j = 0; j < n; j++) {
152                 G[i][j] = sqrt((b[i][0]-a[j][0])*(b[i][0]-a[j][0]) + (b[i][1]-a[j][1])*(b[i][1]-a[j][1]));
153                 r = max(r, G[i][j]);
154             }
155         }
156         while (abs(r-l)>eps) {
157             mm = (l+r)/2;
158             if (check(mm)>k) l = mm;
159             else r = mm;
160         }
161         printf("%.6f
", r+eps);
162     }
163 
164     return 0;
165 }
View Code
原文地址:https://www.cnblogs.com/Phantom01/p/4101930.html