题目来源:http://acm.hdu.edu.cn/showproblem.php?pid=3156
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 246 Accepted Submission(s): 61
4 | zyzamp | 203MS | 292K | 6446B | G++ | 2011-08-09 18:35:59 |
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 }