题目链接
NWERC2017-Problem G-Glyph Recognition
题意
给你n个点,找出一种中心在远点而且有一个点在x轴上的正多边形环覆盖这些点(在一个正多边形中扣去一个与他相似的且平行的正多边形),是这个环的外围面积尽量小,内围面积尽量大,正多边形为正3-8边形,求内部面积与外部面积的最大比值。
做法
二分每种正多边形在x轴上点的横坐标,当计算最大的内围面积时,只要当前多边形内不包含点就可以变大,当计算最小的外围面积时,只要当前多边形内有n个点就可以减小,二分计算每种多边形的答案取max即可。
构造多边形用点根据原点旋转一定度数来做,判一个点是否在多边形内部只需判定他在这个多边形所有向量的左侧即可。
代码
#include<iomanip>
#include<iostream>
#include<math.h>
using namespace std;
const long double eps= 1e-9;
const long double pi = acos(-1.0);
int sgn(long double x)
{
if(fabs(x)<eps) return 0;
if(x<0) return -1;
else return 1;
}
struct Point
{
long double x,y;
Point(){}
Point (long double _x,long double _y)
{
x=_x,y=_y;
}
Point operator -(const Point &b)const
{
return Point(x-b.x,y-b.y);
}
long double operator ^(const Point &b) const
{
return x*b.y-y*b.x;
}
Point rotat(Point p,double angle)
{
Point v=(*this)-p;
double c=cos(angle),s=sin(angle);
return Point(p.x+v.x*c-v.y*s,p.y+v.x*s+v.y*c);
}
};
struct Line
{
Point s,e;
Line(){}
Line(Point _s,Point _e)
{
s=_s,e=_e;
}
int relation(Point p)
{
int c=sgn((p-s)^(e-s));
if(c<0) return 1;
else if(c>0) return 2;
else return 3;
}
};
const int maxn = 1005;
int n;
Point p[maxn],pp[maxn];
Line l[maxn];
int check(long double mid,int pos)
{
long double ang=2.0*pi/(1.0*pos);
pp[0]=Point(mid,0.0);
for(int i=1;i<pos;i++) pp[i]=pp[i-1].rotat(Point(0,0),ang);//旋转获得每个点
for(int i=0;i<pos-1;i++) l[i]=Line (pp[i],pp[i+1]);//按逆时针建边
l[pos-1]=Line(pp[pos-1],pp[0]);
int cnt=0;
for(int i=1;i<=n;i++)
{
int flag=0;
for(int j=0;j<pos;j++) if(l[j].relation(p[i])!=1){flag=1;break;}
if(flag==0) cnt++;
}
return cnt;
}
int main()
{
ios::sync_with_stdio(false);
int pos;
long double up,ans=0;
cin>>n;
for(int i=1;i<=n;i++) cin>>p[i].x>>p[i].y;
for(int i=3;i<=8;i++)
{
long double l=0,r=1e10;
while(r-l>=eps)
{
long double mid=(l+r)/2.0;
if(check(mid,i)==0) l=mid;
else r=mid;
}
up=l*l,l=0,r=1e10;
while(r-l>=eps)
{
long double mid=(l+r)/2.0;
if(check(mid,i)==n) r=mid;
else l=mid;
}
if(up/(l*l)>ans) ans=up/(l*l),pos=i;
}
cout<<pos<<" "<<fixed<<setprecision(10)<<ans<<endl;
return 0;
}