描述:
平分凸多边形面积的线段有无数条,求其中最短的线段长度。
输入:
第一行是凸多边形的顶点数n (3<=n<=5000),接下来是n行顶点坐标,按逆时针顺次输入。
n
x1 y1
. . .
xn yn
输出:
所有平分该多边形面积的线段中,最短的长度值。结果保留6位小数。
输入样例 1
4
0 0
10 0
10 10
0 10
输出样例 1
10.000000
输入样例 2
3
0 0
6 0
3 10
输出样例 2
4.242641
输入样例 3
5
0 0
99999 20000
100000 70000
33344 63344
1 50000
输出样例 3
54475.580092
输入样例 4
6
100 350
101 349
6400 3440
6400 3441
1200 7250
1199 7249
输出样例 4
4559.205002
- 先求出每个顶点在对应边的割点。用N标序,并与当前点用结构体中的link相互“链接”。
- 用i从0号点开始遍历。第i个顶点、i的next顶点以及它们对应的link构成一个四边形。
- 假设Q从B点往C点运动,则对应边一定由于一个P点使PB平行于QB’,因此PQ和BB’一样是该凸多边形的面积平分线,只要找出这个过程中PQ的最短值,便是该四边形中最短的分割线。
- 难点在于如何确定PQ的最短长度。可以运用三分法求单峰极值。
三分适用于求单峰函数的极值。
定理 设f(x)为[a,b]上的单峰函数, x0是它的峰值点,设x1,x2 (x1<x2)是[a,b]上任意两点,那么,
若f(x1)>=f(x2),则x0在[a,x2]上;
若f(x1)<=f(x2),则x0在[x1,b]上;
接下来我们对比一下f(lmid)与f(rmid)的值,若f(lmid)<f(rmid)那么区间就变为lmid∼r否则变为l∼rmid
证明的话也比较简单:
当lmid与rmid在最值的同一侧。由于凸性函数在最大值(最小值)任意一侧都具有单调性,因此,lmid与rmid中,更大(小)的那个 数自然更为靠近最值。此时,我们远离最值的那个区间不可能包含最值,因此可以舍弃。当lmid与rmid在最值的两侧。由于最值在中间的一个区间,因此我们舍弃一个区间后,并不会影响到最值。
double f(double x)
{
return x*x-5*x+6;
}
main()
{
double L,R,lmid,rmid;
L=0; R=5;
while (R-L>1e-8)
{
lmid=L+(R-L)/3;
rmid=R-(R-L)/3;
if (f(lmid)>f(rmid)) L=lmid; else R=rmid;
}
printf("%.3lf",L);
}
5.通过遍历凸多边形所能够构造的所有四边形,并求除它们的最短分割线,再进行比较,便能够求出该凸多边形的最短面积平分线。
#include<iostream>
#include<cstdio>
#include<cmath>
#define M 1e-10
using namespace std;
int n,N;
double area;//多边形面积
double mn=1e18;
struct Point{
double x;
double y;
int next;//用来保存下一个顶点的序号
int link;
};
double Area(Point *&p);//指向引用的指针
void FindLink(Point *&p,int b);
double AreaTri(Point a,Point b,Point c);
void FindShortest(Point *&p,int P,int Q);
double Length(Point a,Point b);
bool Coincidence(Point P,Point Q)