题意:
按照逆时针顶点的顺序给一个凸多边形,再给一个点O,问以点O为圆心,至少以多少为直径画圆才能使这个圆和多边形有至少一个点的交集。
思路:
如果点在多边形内,答案为0
否则,求点到每一段边的距离(点到线段的距离)取最小值即可。
点到线段距离分两种情况:点到线段所在直线的垂线与线段无交点,有交点
题目用到的计算几何知识:
(1)点在多边形内的判定
(2)向量点积判断两射线夹角是钝角还是锐角
(3)点到线段距离求法:叉积求面积 除以 底边
#include <iostream>
#include <cstdio>
#include <cmath>
using namespace std;
#define N 105
struct Point
{
double x, y;
void input() { scanf("%lf%lf",&x,&y); }
} p[N], t;
int n;
double ans;
int pnpoly()
{
int i, j, c = 0;
for (i = 1, j = n; i <= n; j = i++)
if ( ((p[i].y>p[0].y) != (p[j].y>p[0].y)) && (p[0].x < (p[j].x-p[i].x) * (p[0].y-p[i].y) / (p[j].y-p[i].y) + p[i].x) )
c = !c;
return c;
}
double cross(Point &O, Point &P, Point &Q)
{
return ((P.x-O.x)*(Q.y-O.y) - (P.y-O.y)*(Q.x-O.x));
}
double dist(Point &P, Point &Q)
{
return sqrt((Q.x-P.x)*(Q.x-P.x) + (Q.y-P.y)*(Q.y-P.y));
}
bool inRange(Point &A, Point &B)
{
double ijx = B.x-A.x, ijy = B.y-A.y;
double ix = p[0].x-A.x, iy = p[0].y-A.y;
double jx = p[0].x-B.x, jy = p[0].y-B.y;
return (ijx*ix+ijy*iy > 0 && ijx*jx + ijy*jy < 0.0);
}
double height(Point &O, Point &A, Point &B)
{
t = O;
if( !inRange(A,B))
return min(dist(A,O), dist(B,O));
else
return fabs(cross(O,A,B)/dist(A,B));
}
int main()
{
p[0].input();
scanf("%d",&n);
for (int i = 1; i <= n; ++ i)
p[i].input();
if (pnpoly()) puts("0.000");
else
{
ans = 10000;
for (int i = 1; i <= n; ++ i)
ans = min(ans, height(p[0], p[i], p[i==n?1:(i+1)]));
printf("%.3lf\n", 2*ans);
}
}