Radar

题意:有N个城市,M个雷达站,K个操作员,从M个雷达站中选择K个,来覆盖所有的N城市,每个雷达有相同的覆盖半径,问:最小的覆盖半径是多少

一看题意,就知道是个最小支配集问题,最小支配集属于NP难题,找不到多项式解法,所有只能搜索,但是普通的搜索是过不了的,鉴于这种类型的题,可以用一种的特殊的结构--双向链表,于是就可以用DLX来优化这个搜索,而且这题还需要剪枝,据说是A*,表示不懂,找到模板过了。。

可以先二分距离,然后用DLX判断就行了。

 

代码
1 /*最小支配集*/
2 #include<stdio.h>
3 #include<string.h>
4 #include<math.h>
5 #include<stdlib.h>
6  #define INF 0x3fffffff
7  #define EPS 1e-8
8  #define EP 1e-10
9  #define NN 55
10 struct POINT{
11 double x, y;
12 }f[NN], g[NN];
13 double dis[NN][NN];
14
15 int adj[NN][NN];
16 int N, M, K, head;
17
18 int R[NN * NN], L[NN * NN], U[NN * NN], D[NN * NN];
19 int C[NN * NN];//记录每个节点所在列
20 int cntc[NN]; //记录每列包含的节点数
21
22 /*删除第c列*/
23 void remove(int c){
24 int i;
25 for (i = D[c]; i != c; i = D[i]){
26 R[L[i]] = R[i];
27 L[R[i]] = L[i];
28 }
29 }
30 /*恢复第c列*/
31 void resume(int c){
32 int i;
33 for (i = D[c]; i != c; i = D[i]){
34 R[L[i]] = i;
35 L[R[i]] = i;
36 }
37 }
38
39 int h(){
40 bool hash[NN];
41 memset(hash, 0, sizeof(hash));
42
43 int i, j, c;
44 int ans = 0;
45 for (c = R[head]; c != head; c = R[c]){
46 if (!hash[c]){
47 ans ++;
48 for (i = D[c]; i != c; i = D[i]){
49 for (j = R[i]; j != i; j = R[j]){
50 hash[C[j]] = true;
51 }
52 }
53 }
54 }
55 return ans;
56 }
57
58 /*DLX主要部分*/
59 int dfs(int k){
60 if (R[head] == head) return 1;
61 if (k + h() > K) return 0;// A*剪枝
62
63
64 int i, j, c;
65 int Min = INF;
66 for (i = R[head]; i != head; i = R[i]){
67 if (cntc[i] < Min){
68 Min = cntc[i];
69 c = i;
70 }
71 }
72 for (i = D[c]; i != c; i = D[i]){
73 remove(i);
74 for (j = R[i]; j != i; j = R[j]){
75 remove(j);
76 cntc[C[j]]--;
77 }
78 if (dfs(k + 1)) return 1;
79 for (j = L[i]; j != i; j = L[j]){
80 resume(j);
81 cntc[j]++;
82 }
83 resume(i);
84 }
85 return 0;
86 }
87 /*建图*/
88 int Build(){
89 int i, j, now, pre, first;
90 head = 0;
91 for (j = head; j < N; j++){
92 R[j] = j + 1;
93 L[j + 1] = j;
94 }
95 L[head] = j;
96 R[j] = head;
97
98 /*列双向链表*/
99 for (j = 1; j <= N; j++){
100 pre = j;
101 cntc[j] = 0;
102 for (i = 1; i <= M; i++){
103 if (adj[i][j]){
104 now = i * N + j;
105 C[now] = j;
106 cntc[j]++;
107 D[pre] = now;
108 U[now] = pre;
109 pre = now;
110 }
111 }
112 now = j;
113 D[pre] = now;
114 U[now] = pre;
115 if (cntc[j] == 0) return 0;
116 }
117 /*行双向链表*/
118 for (i = 1; i <= M; i++){
119 pre = first = -1;
120 for (j = 1; j <= N; j++){
121 if (adj[i][j]){
122 now = i * N + j;
123 if (pre != -1){
124 R[pre] = now;
125 L[now] = pre;
126 }else{
127 first = now;
128 }
129 pre = now;
130 }
131 }
132 if (first != -1){
133 now = first;
134 R[pre] = now;
135 L[now] = pre;
136 }
137 }
138 return 1;
139 }
140
141 /*判断*/
142 int OK(double mid){
143 int i, j;
144 for (i = 1; i <= M; i++){
145 for (j = 1; j <= N; j++){
146 if (dis[i][j] - mid < EP){
147 adj[i][j] = 1;
148 }else adj[i][j] = 0;
149 }
150 }
151 if (Build())
152 return dfs(0);
153 else return 0;
154 }
155
156 /*二分距离*/
157 double Binary(){
158 double low = 0;
159 double hig = 1500;
160 double mid, ans = -1;
161 while(hig - low > EPS){
162 mid = (low + hig) / 2;
163 if (OK(mid)){
164 ans = mid;
165 hig = mid;
166 }else low = mid;
167 }
168 return ans;
169 }
170 /*计算雷达i到城市j的距离*/
171 double Distance(int i, int j){
172 return sqrt((g[i].x - f[j].x) * (g[i].x - f[j].x)
173 + (g[i].y - f[j].y) * (g[i].y - f[j].y));
174 }
175 /*初始化距离矩阵dis[M][N]*/
176 void Init(){
177 int i, j;
178 for (i = 1; i <= M; i++){
179 for (j = 1; j <= N; j++){
180 dis[i][j] = Distance(i, j);
181 }
182 }
183 }
184 int main()
185 {
186 int T, i;
187 scanf("%d", &T);
188 while(T--){
189 scanf("%d%d%d", &N, &M, &K);
190 for (i = 1; i <= N; i++){
191 scanf("%lf%lf", &f[i].x, &f[i].y);
192 }
193 for (i = 1; i <= M; i++){
194 scanf("%lf%lf", &g[i].x, &g[i].y);
195 }
196 Init();
197 printf("%.6lf\n", Binary());
198 }
199 return 0;
200 }
201

 

 

 

posted on 2010-10-03 21:06  ylfdrib  阅读(1455)  评论(0编辑  收藏  举报