题意:平面上给定n个点的坐标,我们可以选其中3点构成一个圆,当然也就有3段弧,我们定义第K个圆满足条件:
(1)除了已选的3个点,剩下的n-3个点中有K个点在圆内,有n-K-1个点在圆外
(2)保证所有的点在圆的三条弧中其中一条弧的一侧
解析:本题实际上就是得到这样一个结论,满足条件的圆其中有两点一定在这些点的凸包上,并且这两点相邻,这样我们就可以先
求凸包,然后枚举凸包的每条边,设边的端点为A,B,再枚举点B,然后我们把角APB按照从小到大的顺序排序,其中第K+1个就
是我们要求的,对于枚举凸包的每一条边都求出第K+1个点与凸包边的端点形成的圆的半径,记录最小的。
由于点的数目2000,比较大,直接枚举会超时。所以采用堆优化。
#include <iostream>
#include <algorithm>
#include <stdio.h>
#include <cmath>
using namespace std;
const int N=2005;
struct Point
{
int x,y;
};
struct HEAP
{
double var;
int id;
};
HEAP heap[N];//小顶堆
Point p[N];
int stack[N];
bool readIn(int &N,int &K)
{
if(scanf("%d%d",&N,&K)==EOF)
return false;
for(int i=1;i<=N;i++)
scanf("%d%d",&p[i].x,&p[i].y);
return true;
}
int cross(Point A,Point B,Point C)
{
return (B.x-A.x)*(C.y-A.y)-(B.y-A.y)*(C.x-A.x);
}
bool cmp(const Point &a,const Point &b)
{
return cross(p[1],a,b)>0 ;
}
double dist(Point A,Point B)
{
return sqrt((A.x-B.x)*(A.x-B.x)+(A.y-B.y)*(A.y-B.y));
}
double getAng(const Point &a,const Point &b,const Point &c)
{
double A,B,C;
C=dist(b,c);
A=dist(a,b);
B=dist(a,c);
double ang_a=acos((A*A+B*B-C*C)/(2*A*B));
return ang_a;
}
/**根据角a和b对点排序*/
bool heapCmp(const HEAP &a,const HEAP &b)
{
return a.var>b.var;
}
void insert(const HEAP &a,int &cnt)
{
heap[++cnt]=a;
int j=cnt;
while(j>1)
{
if(heapCmp(heap[j/2],heap[j]))
{
swap(heap[j/2],heap[j]);
j/=2;
}
else break;
}
}
void heapDown(const int &id,const int &cnt)
{
int lc=id*2,rc=id*2+1,j=id;
if(lc<=cnt&&heapCmp(heap[j],heap[lc])) j=lc;
if(rc<=cnt&&heapCmp(heap[j],heap[rc])) j=rc;
if(j!=id)
{
swap(heap[id],heap[j]);
heapDown(j,cnt);
}
return;
}
/**已知三点求三角形的面积*/
double triangleArea(const Point &a,const Point &b,const Point &c)
{
return fabs(cross(a,b,c))/2.0;
}
/**已知圆上三点求圆半径*/
double getRadius(const Point &a,const Point &b,const Point &c)
{
double A=dist(a,b);
double B=dist(a,c);
double C=dist(b,c);
return (A*B*C)/(triangleArea(a,b,c)*4.0);
}
void Solve(const int &N,const int &K)
{
int id=1;
for(int j=1;j<=N;j++)
if(p[id].x<p[j].x||(p[id].x==p[j].x&&p[id].y<p[j].y))
id=j;
swap(p[1],p[id]);
sort(p+2,p+N+1,cmp);
int top=0;
stack[++top]=1,stack[++top]=2;
for(int i=3;i<=N;i++)
{
while(top>1&&cross(p[stack[top-1]],p[stack[top]],p[i])<0) top--;
stack[++top]=i;
}
stack[++top]=stack[1];
double ans=1000000000;
HEAP tmp;
for(int i=1;i<top;i++)
{
int cnt=0;
for(int j=1;j<=N;j++)
{
if(j!=stack[i]&&j!=stack[i+1])
{
tmp.id=j;
tmp.var=getAng(p[j],p[stack[i]],p[stack[i+1]]);
if(cnt<K) insert(tmp,cnt);
else
{
if(heapCmp(tmp,heap[1]))
{
heap[1]=tmp;
heapDown(1,cnt);
}
}
}
}
double tmp=getRadius(p[stack[i]],p[stack[i+1]],p[heap[1].id]);
ans=ans>tmp? tmp:ans;
}
printf("%.2lf\n",ans);
}
int main()
{
int N,K;
while(readIn(N,K))
{
K++;
Solve(N,K);
}
return 0;
}