GYM 101606 B.Breaking Biscuits(计算几何)

Description

给出一个 n 个顶点的多边形,为使该多边形经过适当三维旋转可以通过一个直径为 R 的圆形通道, R 的最小值为多少

Input

第一行一整数 n 表示点数,之后逆时针输入 n 个顶点的坐标 ( 3 n 100 , 10 5 x , y 10 5 )

Output

输出 R 的最小值

Sample Input

4
0 0
5 0
5 2
0 2

Sample Output

2.0

Solution

枚举两个顶点,求出两点所连直线两边顶点到该条直线的距离最大值之和即为以这两点连线为方向通过时需要 R 的最小值,维护最小值即为答案

对于为什么最优解必然以两个顶点之间连线为方向,用反证法,把问题转化为将该多边形放入两条平行于 y 轴的直线 x = x 1 x = x 2 构成的条形区域,若所有点的横坐标都不同,假设该多边形与这两条直线的切点为 A B ,那么 A , B 两点的相邻顶点必然都在条形区域内部,进而我们可以以 A , B 中的一点(假设是 B 点)为圆心对整个多边形进行适当旋转(如果 B 点纵坐标大于 A 点纵坐标则逆时针旋转,否则顺时针旋转)直至某一个顶点 C A B 的横坐标相同,显然如此旋转后整个多边形的横坐标范围要小于 [ x 1 , x 2 ] ,也即存在一个更优的解,与最优解定义矛盾,故最优解必然是以两个顶点连线为方向的

Code

#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<vector>
#include<queue>
#include<map>
#include<set>
#include<ctime>
using namespace std;
typedef long long ll;
typedef pair<int,int>P;
const int INF=0x3f3f3f3f,maxn=105;
struct Point
{
    int x,y;
    Point operator-(const Point &b)const
    {
        Point c;
        c.x=x-b.x,c.y=y-b.y;
        return c;
    }
}p[maxn];
int n;
ll M(Point a,Point b)
{
    return 1ll*a.x*b.y-1ll*a.y*b.x;
}
double D(Point a,Point b)
{
    return sqrt(1.0*(b.x-a.x)*(b.x-a.x)+1.0*(b.y-a.y)*(b.y-a.y));
}
int main()
{
    scanf("%d",&n);
    for(int i=0;i<n;i++)scanf("%d%d",&p[i].x,&p[i].y);
    double ans=1e18;
    for(int i=0;i<n;i++)
        for(int j=i+1;j<n;j++)
        {
            double temp1=0,temp2=0;
            for(int k=0;k<n;k++)
            {
                ll S=M(p[k]-p[i],p[j]-p[i]);
                if(S>0)temp1=max(temp1,abs(S)/D(p[i],p[j]));
                else temp2=max(temp2,abs(S)/D(p[i],p[j]));
            }
            ans=min(ans,temp1+temp2);
        }
    printf("%.9f\n",ans);
    return 0;
}

猜你喜欢

转载自blog.csdn.net/v5zsq/article/details/80449837
今日推荐