版权声明:转载注明下出处就行了。 https://blog.csdn.net/LJD201724114126/article/details/84330763
题目链接:poj 3384
题意:顺时针给n个点,给你两个半径相等的圆,将两个半径为 r 的圆放入一个多边形中,两圆可以重叠,问两个圆占据最大面积时圆心坐标是多少?
题解:我们先求出凸多边形每条边内缩r之后的核,那么这两圆的圆心坐标肯定在这核里面,这时我们就枚举核顶点,找出最远距离的两个顶点作为两个圆心坐标,因为两圆心相离越远,它们两个占用的面积就越大。
这题我真的想开骂了,一直Output Limit Exceeded 和 wa ,之后把叉积判断那里>0的改成>esp,就过了。艹。
以后凡是遇到0的,全用esp代替。
///半平面交
#include<cmath>
#include<cstdio>
#include<iostream>
#include<algorithm>
using namespace std;
const int maxn=110;
struct point
{
double x,y;
point(){}
point(double _x,double _y){
x=_x;y=_y;
}
}poly[maxn];///存储半平面交后的交点
point operator + (point a,point b) { return point(a.x+b.x,a.y+b.y);}
point operator - (point a,point b) { return point(a.x-b.x,a.y-b.y);}
point operator * (point a,double p) { return point(a.x*p,a.y*p);}
point operator / (point a,double p) { return point(a.x/p,a.y/p);}
bool operator < (const point &a,const point &b){
return a.x<b.x||(a.x==b.x&&a.y<b.y);
}
const double esp=1e-8;
int dcmp(double x){
if(fabs(x)<esp) return 0;
else return x<0?-1:1;
}
bool operator == (const point &a,const point &b){
return dcmp(a.x-b.x)==0&&dcmp(a.y-b.y)==0;
}
double Cross(point P,point Q)
{
return P.x*Q.y-P.y*Q.x;
}
double Length(point A) { return sqrt(A.x*A.x+A.y*A.y);}
struct LINE
{
point s,t;
double angle;
LINE(){}
LINE(point _s,point _t){
s=_s;t=_t;
angle=atan2(t.y-s.y,t.x-s.x);
}
}L[maxn],dq[maxn],trans[maxn];///存储向量,半平面交时用到的双端队列dq
point Getlinenode(LINE a,LINE b)
{
point P=a.s,v=a.t-a.s; ///点,向量
point Q=b.s,w=b.t-b.s;
point u=P-Q;
double t=Cross(w,u)/Cross(v,w);
return P+v*t;
}
bool cmp(LINE P,LINE Q) ///两向量方向相同,靠下的优先
{
if(fabs(P.angle-Q.angle)<esp)
return Cross(P.s-P.t,Q.s-P.t)>esp;
return P.angle<Q.angle;
}
bool Onright(LINE L,point p){ ///判断点p在直线L的右边,
return Cross(L.s-L.t,p-L.t)>esp;
}
void Half(int n,int &m)
{
sort(L,L+n,cmp);
int l=0,r=1;
m=1;
for(int i=1;i<n;++i)///筛掉同斜率,保留靠下的向量,其余不要
if(fabs(L[i].angle-L[i-1].angle)>esp)L[m++]=L[i];
n=m;
m=0;
dq[0]=L[0],dq[1]=L[1];
for(int i=2;i<n;++i)
{
if(dcmp(Cross(dq[r].s-dq[r].t,dq[r-1].s-dq[r-1].t))==0||dcmp(Cross(dq[l].s-dq[l].t,dq[l+1].s-dq[l+1].t))==0) return;
///交点在直线的右边,舍去
while(l<r&&Onright(L[i],Getlinenode(dq[r],dq[r-1]))>0)--r;
while(l<r&&Onright(L[i],Getlinenode(dq[l],dq[l+1]))>0)++l;
dq[++r]=L[i];
}
///判断下头尾向量
while(l<r&&Onright(dq[l],Getlinenode(dq[r],dq[r-1]))>0)--r;
while(l<r&&Onright(dq[r],Getlinenode(dq[l],dq[l+1]))>0)++l;
dq[++r]=dq[l];///将头向量加到尾部
for(int i=l;i<r;++i)
poly[m++]=Getlinenode(dq[i],dq[i+1]);///存储m+1个(范围在[0,m])半平面交点
}
double h;
void Change(int n) ///将所有边往内缩进h距离
{
double dx,dy,len;
for(int i=0;i<n;i++)
{
len=Length(trans[i].s-trans[i].t);
dx=(trans[i].s.y-trans[i].t.y)*h/len;
dy=(trans[i].t.x-trans[i].s.x)*h/len;
L[i].s.x=trans[i].s.x+dx;
L[i].s.y=trans[i].s.y+dy;
L[i].t.x=trans[i].t.x+dx;
L[i].t.y=trans[i].t.y+dy;
L[i].angle=trans[i].angle;
}
}
void solve(int n)
{
int m;
Change(n);
Half(n,m);
point r1,r2;
double dis=-999;
for(int i=0;i<m;i++)
{
// printf("%f %f\n",poly[i].x,poly[i].y);
for(int j=0;j<m;j++)
{
if(dcmp(dis-Length(poly[i]-poly[j]))<0){
dis=Length(poly[i]-poly[j]);
r1=poly[i];r2=poly[j];
}
}
}
printf("%.4f %.4f %.4f %.4f\n",r1.x+esp,r1.y+esp,r2.x+esp,r2.y+esp);
}
int main()
{
int n,m,t;
while(~scanf("%d%lf",&n,&h))
{
for(int i=0;i<n;++i)
scanf("%lf%lf",&poly[i].x,&poly[i].y);
poly[n]=poly[0];
for(int i=0;i<n;++i)
{
trans[i]=LINE(poly[i+1],poly[i]);
}
solve(n);
}
return 0;
}
/*
5 2
-2 0
-5 3
0 8
7 3
5 0
-2.171573 3.000000
-1.171573 2.000000
3.929632 2.000000
4.261709 2.498115
0.216195 5.387768
-2.1716 3.0000 4.2617 2.4981
4 3
0 0
0 8
10 8
10 0
3.000000 3.000000
7.000000 3.000000
7.000000 5.000000
3.000000 5.000000
3.0000 3.0000 7.0000 5.0000
*/