2015
04-14

# Perfect Faceless Void

DotA is a popular game now. There is a hero called Faceless Void (Darkterror,FV). The hero has a powerful skill called “Chronosphere”. This skill is described as follows: FV can create a Time Enchantment that neither the enemy units nor the friend units in it can move except FV himself. We can treat the Time Enchantment as a circle. Any unit which is in the circle or just on the edge of the circle can’t move.

Now a new Crazy (Imba) version of the game has been issued. In the new version, FV can control the size of the Time Enchantment (the radius of the circle). More bigger the circle is, more mana(magic value, blue) FV costs. What’s more, there is a new set about the unit which is just on the edge of the circle: if the unit is an enemy, it must remain stationary. Otherwise, the unit is free of the skill. Certainly, a unit in the circle must remain stationary whether it is an enemy or a friend.

Then come the problem, there are n (1 <= n <= 10000) enemy units and m (1 <= m <= 10000) friend units in the two dimensional plane, every unit can be treated as a point which is described by a coordinate (x,y). As a perfect player, FV must make sure that all the n enemy units are affected by the skill and all the m friend units are free of it. In additional, FV should choose a solution that cost least mana. How to set the center of the Time Enchantment and the radius of it? It is ensured that there always exists a solution.

There are several test cases (about 50). The first line consists of two integers n and m (1<= n, m <= 10000) indicate the number of enemy units and the number of friend units. Then there are n+m lines, first n lines describe the coordinates of the n enemy units, and the last m lines describe the coordinates of the m friend units. Every line contains two real numbers.

There are several test cases (about 50). The first line consists of two integers n and m (1<= n, m <= 10000) indicate the number of enemy units and the number of friend units. Then there are n+m lines, first n lines describe the coordinates of the n enemy units, and the last m lines describe the coordinates of the m friend units. Every line contains two real numbers.

2 1
0.0 0.0
2.0 0.0
1.0 2.0

2 1
0.0 0.0
2.0 0.0
1.0 1.0

2 2
0.0 0.0
4.0 0.0
2.0 1.0
2.0 2.0

1.000 0.000
1.000
1.000 0.000
1.000
2.000 -1.500
2.500

/*
*最小包围圆随机增量O(n)变形
* by tju_accry
*
*本机测试时间：
*real	0m0.957s
*user	0m0.944s
*sys	0m0.012s

*/
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
using namespace std;

#define sqr(a) ((a)*(a))
#define trarea(p) fabs ((vdet(p[0],p[1],p[2])/2.0))
double const EPS = 1e-12;
int const maxn = 20011;
struct point{double x,y;int flag;};
struct circle{
point c;
double r;
};
inline double vdet(point op,point p1,point p2){
return (p1.x-op.x)*(p2.y-op.y)-(p2.x-op.x)*(p1.y-op.y);
}
inline double dis(point a,point b){
return sqr(a.x-b.x)+sqr(a.y-b.y);
}
inline point get_out_circle(point p[]){  //三角形外接圆圆心
double c1,c2,xa,xb,xc,ya,yb,yc;
point o;
xa=p[0].x,xb=p[1].x,xc=p[2].x;
ya = p[0].y,yb = p[1].y,yc = p[2].y;
c1 = (sqr(xa) + sqr(ya) - sqr(xb) - sqr(yb))/2.0;
c2 = (sqr(xa) + sqr(ya) - sqr(xc) - sqr(yc))/2.0;
o.x = (c1*(ya-yc)-c2*(ya-yb))/((xa-xb)*(ya-yc)-(xa-xc)*(ya-yb));
o.y = (c1*(xa-xc)-c2*(xa-xb))/((ya-yb)*(xa-xc)-(ya-yc)*(xa-xb));
return o;
}
inline double get_out_r(point p[]){  //三角形外接圆半径
double a = dis(p[0],p[1]),b = dis(p[1],p[2]),c = dis(p[2],p[0]),s = trarea(p);
return a*b*c/sqr(4*s);
}
point must_on[3],p[maxn];
circle mc;
inline void get_circle(int tm){  //一点，两点圆，三点圆
switch(tm){
case 0:mc.r = -1;
break;
case 1:mc.r = 0,mc.c = must_on[0];
break;
case 2:{
mc.r = dis(must_on[0],must_on[1])/4.0;
mc.c.x = (must_on[0].x+must_on[1].x)/2.0;
mc.c.y = (must_on[0].y + must_on[1].y)/2.0;
}break;
case 3:{
mc.r = get_out_r(must_on);
mc.c = get_out_circle(must_on);
}break;
}
}
inline void min_circle(int t,int ton){
get_circle(ton);
if(ton >= 3)return;
for(int i = 0; i < t; ++i){
/*
//求一个点集的最小包围圆
if(dis(mc.c,p[i]) > mc.r + EPS){
must_on[ton] = p[i];
min_circle(i,ton+1);
}
*/

/*本题*/
if(p[i].flag == 1){
if(dis(mc.c,p[i]) > mc.r + EPS){  //A集合点在圆内或圆周上
must_on[ton] = p[i];
min_circle(i,ton+1);
}
}
else {
if(dis(mc.c,p[i]) + EPS < mc.r){  //B集合的点不在圆内（可以在圆周上）
must_on[ton] = p[i];
min_circle(i,ton+1);
}
}

}
}
int main(){
int n,m;
//freopen("data.in","r",stdin);
//freopen("data.out","w",stdout);
while (scanf("%d%d",&n,&m) != EOF){
for(int i = 0; i < n; ++i){
scanf("%lf%lf",&p[i].x,&p[i].y);
p[i].flag = 1;
}

for(int i = n; i < m + n; ++i){
scanf("%lf%lf",&p[i].x,&p[i].y);
p[i].flag = 2;
}
n = n + m;
random_shuffle(p,p+n); //随机化序列元素
min_circle(n,0);
printf("%.3lf %.3lf\n%.3lf\n",mc.c.x,mc.c.y,sqrt(mc.r));
}
return 0;
}

1. 换句话说，A[k/2-1]不可能大于两数组合并之后的第k小值，所以我们可以将其抛弃。
应该是，不可能小于合并后的第K小值吧