熬夜肝没了
多边形面积的最长平分线
描述
平分凸多边形面积的线段有无数条,求其中最长的线段长度。
输入
第一行是凸多边形的顶点数n (3<=n<=5000),接下来是n行顶点坐标,按逆时针顺次输入。
n
x1 y1
. . .
xn yn
输出
所有平分该多边形面积的线段中,最长的长度值。结果保留6位小数。
把自己卡到的点:
- 点乘、叉乘 进一步理解判断点在直线的左右侧问题
- 平面多边形坐标计算公式 ->鞋带定理 (注意回龙关系 最后的n-1要和0进行关联)
- 逆时针的顺序进行组合三角形 防止重叠面积
- 向量λ比例切割求坐标 ->同高三角形的面积比为底边边 (AP=0P-OA,AP=λAB,OP=AP+0A)
- 平面直线计算公式
#include<iostream>
#include<cmath>
#include<iomanip>
using namespace std;
#define zero 1E-8
typedef struct{
double x;
double y;
}Point;
double S_new_calc(Point a,Point b,Point c){
double t1,t2,t3,t4,t5,t6,sum;
t1=a.x*b.y;
t2=a.y*b.x;
t3=b.x*c.y;
t4=b.y*c.x;
t5=c.x*a.y;
t6=c.y*a.x;
sum=0.5*fabs(t1+t3+t5-t2-t4-t6);
return sum;
}
double vec_calc(Point a,Point b,double k,Point base){
double tx,ty;
double vx,vy,dis;
vx=b.x-a.x,vy=b.y-a.y;
vx=k*vx,vy=k*vy;
tx=vx+a.x,ty=vy+a.y;
dis=sqrt( (base.x-tx)*(base.x-tx) + (base.y-ty)*(base.y-ty) );
return dis;
}
int main(){
Point* point;
int i,n,index1,index2,*index;
double S,S_new,S_test,k,max,dis;
S=S_new=S_test=max=0;
cin>>n;
point = new Point[n+20];
index = new int[n+20];
for(i=0;i<n;i++) cin>>point[i].x>>point[i].y;
for(i=0;i<n-1;i++){ //多边形面积
S= S + (point[i].x*point[i+1].y - point[i].y*point[i+1].x);
}
S= S + (point[n-1].x*point[0].y - point[n-1].y*point[0].x);
S=fabs(S)/2.0;
for(i=0;i<n;i++){ //各点为首的分割体
S_new=S_test=0;
index[0]=i;
for(int j=1;j<n;j++) if(j+i<n) index[j]=j+i;else if(j+i>=n) index[j]=j+i-n;
// for(int j=0;j<n;j++) cout<<index[j]<<" ";
// cout<<endl;
index1=1,index2=index1+1;
while(true){
S_test=S_test+S_new_calc(point[index[index1]],point[index[index2]],point[index[0]]);
if(S_test-S/2>=zero) break;
S_new=S_test;
index1=index2++;
}
// cout<<setiosflags(ios::fixed)<<setprecision(6)<<"S:"<<S<<" S_test:"<<S_test<<endl;
k=(S*0.5-S_new)/(S_test-S_new);
dis=vec_calc(point[index[index1]],point[index[index2]],k,point[index[0]]);
max=dis-max>zero?dis:max;
}
cout<<setiosflags(ios::fixed)<<setprecision(6)<<max;
delete []point;
delete []index;
return 0;
}