1. 程式人生 > >【NWERC2017-Problem G-Glyph Recognition 】二分+計算幾何

【NWERC2017-Problem G-Glyph Recognition 】二分+計算幾何

題目連結

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; }