题目来源:http://acm.hdu.edu.cn/showproblem.php?pid=3156
Repair Depots
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 246 Accepted Submission(s): 61
Problem Description
RoboCorp Oregon has already deployed several of its PoliceBots throughout the state, and suddenly they have remembered the importance of being able to repair these bots when they break. They are willing to build only a limited number of repair depots in the state, and they want to locate these depots so that each PoliceBot's city is within a given distance of some depot.
![](http://acm.hdu.edu.cn/data/images/C239-1008-1.jpg)
You are given the locations of where the n (1 <= n <= 16) PoliceBots have been deployed, and the maximum number (1 <= c <= n) of repair depots that RoboCorp is willing to construct. Your job is to locate these repair depots to minimize the distance any bot has to be transported for repair, and return what that maximum distance is. You can assume that any bot can be repaired at any depot.
![](http://acm.hdu.edu.cn/data/images/C239-1008-1.jpg)
You are given the locations of where the n (1 <= n <= 16) PoliceBots have been deployed, and the maximum number (1 <= c <= n) of repair depots that RoboCorp is willing to construct. Your job is to locate these repair depots to minimize the distance any bot has to be transported for repair, and return what that maximum distance is. You can assume that any bot can be repaired at any depot.
Input
The first line contains the integer t (1 <= t <= 350), the number of cases. Each case starts with a line containing n and c. Following this line is one line per deployed bot; that line contains two floating point values, separated by a single space, giving the Cartesian coordinates of the bot. Each such value will be between 0.0 and 10.0, inclusive (NOTE: the Sample Input shows integer values for brevity).
Output
You are to print for each input set the minimum value that can be obtained, such that each PoliceBot is within that distance of some depot. You should print your result with at least one digit before and exactly six digits after the decimal point; your value should be within 5e-7 of the true result. To make round-off error less of a concern, the true result will never have a 4 or a 5 as the seventh digit after the decimal point.
Sample Input
2
9 3
1 1
1 2
1 3
2 1
2 2
2 3
3 1
3 2
3 3
4 2
0 0
1 1
2 4
3 9
Sample Output
1.000000
2.236068
比较有一定难度的Dacning Links了。题目大意:给n个村庄,让建一些车站(假设),使所有村庄到这些车站的最短距离 中的最大者 最小。。
思路:我刚开建图的思想有些问题,我也是枚举任意两点,二分半径,不过取圆心为这两点的中点。
后来看了下解题报告: 二分半径,然后枚举任意两点,把这两点靠在圆上,求出圆心的坐标,这时一般会有两个圆心,再分别对每一个圆心进行讨论。
求圆心那一点,看似简单,谁知道还要几个函数。没看计算几何,这一部分是让队友写的。。
这题需要优化,不然又可能会超时,稍微优化一下就不会超时了,比如,如果两个圆心覆盖的点一样,那第二个圆心就不必要加了。。
如果一个圆心覆盖的点是另一个圆心覆盖的点的子集的话,那这个圆心也可以不加,但是如果若想把所有的子集都标记下来,也是很费时的,
我也是只标记了一部分。。
至此,Dancing Links 已经刷了9道了。。也算告一段落了,下一部分就全力进攻搜索,启发式搜索,A*,IDA*。。。
交了N次,最后只能优化到203ms了。。
4 | zyzamp | 203MS | 292K | 6446B | G++ | 2011-08-09 18:35:59 |
贴下我很丑陋的代码吧:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 # include<stdio.h>
2 # include<string.h>
3 # include<stdlib.h>
4 # include<math.h>
5 const int CCC=20;
6 const int RR=400;
7 const int V=8000;
8 const double eps=1e-7;
9 const int N=65550;
10 bool hash[N];
11 int st[N];
12 const double pi = acos(-1.0);
13 int U[V],D[V];
14 int L[V],R[V];
15 int C[V];
16 int size,S[CCC],H[RR],n,m;
17 int dir[17]={1,2,4,8,16,32,64,128,256,512,1024,2048,4096,8192,16384,32768,65536};
18 struct node{
19 double x,y;
20 }s[20];
21 struct point{
22 double x,y;
23 }cnt,cnt1;
24 double Dis(point a,point b){
25 return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y));
26 }
27
28 //向量的旋转 //底边线段ab 绕a逆时针旋转角度A,b->b1,sinl是sinA的值。
29 point Whirl(double cosl, double sinl, point a, point b)
30 {
31 b.x -= a.x; b.y -= a.y;
32 point c;
33 c.x = b.x * cosl - b.y * sinl + a.x;
34 c.y = b.x * sinl + b.y * cosl + a.y;
35 return c;
36 }
37
38 //求两直线的交点(先判断相交)
39 point inst(point u1,point u2,point v1,point v2)
40 {
41 point ans = u1;
42 double t = ((u1.x - v1.x)*(v1.y - v2.y) - (u1.y - v1.y)*(v1.x - v2.x))/
43 ((u1.x - u2.x)*(v1.y - v2.y) - (u1.y - u2.y)*(v1.x - v2.x));
44 ans.x += (u2.x - u1.x)*t;
45 ans.y += (u2.y - u1.y)*t;
46 return ans;
47 }
48 //求不平行两直线的交点
49 point fun(point a,point b,double r)
50 {
51 double l=Dis(a,b);
52 double ans=acos((l/2)/r);//弧度
53 point k1=Whirl(cos(ans),sin(ans),a,b);
54 point k2=Whirl(cos(ans),-sin(ans),b,a);
55 point cent=inst(a,k1,b,k2);
56 return cent;
57 }
58 void Link(int r,int c)
59 {
60 S[c]++;C[size]=c;
61 U[size]=U[c];D[U[c]]=size;
62 D[size]=c;U[c]=size;
63 if(H[r]==-1) H[r]=L[size]=R[size]=size;
64 else
65 {
66 L[size]=L[H[r]];R[L[H[r]]]=size;
67 R[size]=H[r];L[H[r]]=size;
68 }
69 size++;
70 }
71 void remove(int c)
72 {
73 int i;
74 for(i=D[c];i!=c;i=D[i])
75 L[R[i]]=L[i],R[L[i]]=R[i];
76 }
77 void resume(int c)
78 {
79 int i;
80 for(i=U[c];i!=c;i=U[i])
81 L[R[i]]=R[L[i]]=i;
82 }
83 int h()
84 {
85 int i,j,k,count=0;
86 bool visit[20];
87 memset(visit,0,sizeof(visit));
88 for(i=R[0];i;i=R[i])
89 {
90 if(visit[i]) continue;
91 count++;
92 visit[i]=1;
93 for(j=D[i];j!=i;j=D[j])
94 {
95 for(k=R[j];k!=j;k=R[k])
96 visit[C[k]]=1;
97 }
98 }
99 return count;
100 }
101 int Dance(int k)
102 {
103 int i,j,Min,c;
104 if(k+h()>m) return 0;
105 if(!R[0]) return 1;
106 for(Min=RR,i=R[0];i;i=R[i])
107 if(S[i]<Min) Min=S[i],c=i;
108 for(i=D[c];i!=c;i=D[i])
109 {
110 remove(i);
111 for(j=R[i];j!=i;j=R[j])
112 {
113 remove(j);
114 }
115 if(Dance(k+1)) return 1;
116 for(j=L[i];j!=i;j=L[j])
117 resume(j);
118 resume(i);
119 }
120 return 0;
121 }
122 double dis(double x1,double y1,double x2,double y2)
123 {
124 return sqrt((x2-x1)*(x2-x1) + (y2-y1)*(y2-y1));
125 }
126 int cmp(const void *a,const void *b)
127 {
128 return *(int *)a - *(int *)b;
129 }
130 int main()
131 {
132 int i,j,ncase,r,k,bit,sum;
133 double left,right,mid,ansx,ansy,ans,num;
134 point a,b;
135 scanf("%d",&ncase);
136 while(ncase--)
137 {
138 scanf("%d%d",&n,&m);
139 for(i=1;i<=n;i++)
140 scanf("%lf%lf",&s[i].x,&s[i].y);
141 left=0.0;
142 right=7.1;
143 ans=7.1;
144 while(right>=left)
145 {
146 for(i=0;i<=n;i++)
147 {
148 S[i]=0;
149 U[i]=D[i]=i;
150 L[i+1]=i;R[i]=i+1;
151 }R[n]=0;
152 size=n+1;
153 memset(H,-1,sizeof(H));
154 memset(hash,0,sizeof(hash));
155 mid=(left+right)/2;
156 r=0;
157 sum=0;
158 for(i=1;i<=n;i++)
159 {
160 ansx=s[i].x;ansy=s[i].y;
161 bit=0;//存一种状态
162 for(j=1;j<=n;j++)
163 if(dis(s[j].x,s[j].y,ansx,ansy)<=mid) bit+=dir[j-1];
164 if(!hash[bit]) {hash[bit]=1;st[++sum]=bit;}
165 }
166 //开始的时候先把以每个点为圆心的加进来,防止m灰常大的情况
167 for(i=1;i<=n;i++)
168 {
169 for(j=i+1;j<=n;j++)
170 {
171 num=dis(s[i].x,s[i].y,s[j].x,s[j].y);
172 if(num<2*mid)
173 {
174 a.x=s[i].x;a.y=s[i].y;
175 b.x=s[j].x;b.y=s[j].y;
176 cnt=fun(a,b,mid);//第一个圆心
177 ansx=(a.x+b.x)/2;
178 ansy=(a.y+b.y)/2;
179 cnt1.x=2*ansx-cnt.x;
180 cnt1.y=2*ansy-cnt.y;//第二个圆心
181 bit=0;
182 for(k=1;k<=n;k++)
183 {
184 if(k==i) {bit+=dir[i-1];continue;}
185 if(k==j) {bit+=dir[j-1];continue;}//这个地方特别注意,必须把这两种情况特别考虑,因为i和j到圆心的距离刚好是mid
186 //但是由于存在精度问题,这个距离会比mid小,也就是不满足下式。。
187 if(dis(s[k].x,s[k].y,cnt.x,cnt.y)<=mid) bit+=dir[k-1];
188 }
189 if(!hash[bit]) {hash[bit]=1;st[++sum]=bit;}
190 bit=0;
191 for(k=1;k<=n;k++)
192 {
193 if(k==i) {bit+=dir[i-1];continue;}
194 if(k==j) {bit+=dir[j-1];continue;}
195 if(dis(s[k].x,s[k].y,cnt1.x,cnt1.y)<=mid) bit+=dir[k-1];
196 }
197 if(!hash[bit]) {hash[bit]=1;st[++sum]=bit;}
198 }
199 else if(num==2*mid)//只有一个圆心的情况
200 {
201 ansx=(s[i].x+s[j].x)/2;
202 ansy=(s[i].y+s[j].y)/2;
203 bit=0;
204 for(k=1;k<=n;k++)
205 {
206 if(k==i) {bit+=dir[i-1];continue;}
207 if(k==j) {bit+=dir[j-1];continue;}
208 if(dis(s[k].x,s[k].y,ansx,ansy)<=mid) bit+=dir[k-1];
209 }
210 if(!hash[bit]) {hash[bit]=1;st[++sum]=bit;}
211 }
212 }
213 }
214 qsort(st+1,sum,sizeof(st[1]),cmp);
215 for(i=sum;i>=1;i--)
216 {
217 for(j=1;j<=n;j++)
218 if(st[i]&dir[j-1]) hash[st[i]-dir[j-1]]=0;//这里只是标记了一部分子集
219 if(hash[st[i]]==0) continue;
220 r++;
221 for(j=1;j<=n;j++)
222 if(st[i]&dir[j-1]) {Link(r,j);hash[dir[j-1]]=0;}//再标记一部分子集
223 }
224 if(Dance(0)) {ans=mid;right=mid-eps;}
225 else left=mid+eps;
226 }
227 printf("%.6lf\n",ans);
228 }
229 return 0;
230 }