题目链接:http://poj.org/problem?id=3525
The main land of Japan called Honshu is an island surrounded by the sea. In such an island, it is natural to ask a question: “Where is the most distant point from the sea?” The answer to this question for Honshu was found in 1996. The most distant point is located in former Usuda Town, Nagano Prefecture, whose distance from the sea is 114.86 km.
In this problem, you are asked to write a program which, given a map of an island, finds the most distant point from the sea in the island, and reports its distance from the sea. In order to simplify the problem, we only consider maps representable by convex polygons.
Input
The input consists of multiple datasets. Each dataset represents a map of an island, which is a convex polygon. The format of a dataset is as follows.
n | ||
x1 | y1 | |
⋮ | ||
xn | yn |
Every input item in a dataset is a non-negative integer. Two input items in a line are separated by a space.
n in the first line is the number of vertices of the polygon, satisfying 3 ≤ n ≤ 100. Subsequent n lines are the x- and y-coordinates of the n vertices. Line segments (xi, yi)–(xi+1, yi+1) (1 ≤ i ≤ n − 1) and the line segment (xn, yn)–(x1, y1) form the border of the polygon in counterclockwise order. That is, these line segments see the inside of the polygon in the left of their directions. All coordinate values are between 0 and 10000, inclusive.
You can assume that the polygon is simple, that is, its border never crosses or touches itself. As stated above, the given polygon is always a convex one.
The last dataset is followed by a line containing a single zero.
Output
For each dataset in the input, one line containing the distance of the most distant point from the sea should be output. An output line should not contain extra characters such as spaces. The answer should not have an error greater than 0.00001 (10−5). You may output any number of digits after the decimal point, provided that the above accuracy condition is satisfied.
Sample Input
4 0 0 10000 0 10000 10000 0 10000 3 0 0 10000 0 7000 1000 6 0 40 100 20 250 40 250 70 100 90 0 70 3 0 0 10000 10000 5000 5001 0
Sample Output
5000.000000 494.233641 34.542948 0.353553
题目翻译:
日本的主要土地叫本州,是一个被大海包围的岛屿。在这样一个岛上,很自然地会问一个问题:"离海最远的地方在哪里?本州的这个问题的答案是在1996年找到的。最远的点位于长野县前乌苏达镇,距离海面114.86公里。
在这个问题中,你被要求写一个程序,给出一个岛屿的地图,找到离岛上最远的点,并报告它离大海的距离。为了简化问题,我们只考虑可用凸面表示的地图。
输入
输入由多个数据集组成。每个数据集表示岛屿的地图,该地图是凸面。数据集的格式如下所示。
n | ||
x1 | y1 | |
·000年 | ||
xn | yn n |
数据集中的每个输入项都是非负整数。一行中的两个输入项由空格分隔。
第一行中的 n 是多边形的顶点数,满足 3 = n = 100。后续 n 条线是n顶点的x和y坐标。线段 ( xi, yi) + (xi + 1, yi=1) 和线段 (xn,yn)*(x1, y1) 按逆时针顺序形成多边形的边框。也就是说,这些线段在其方向的左侧看到多边形的内部。所有坐标值都在 0 和 10000 之间,包括。
您可以假定多边形很简单,也就是说,它的边框从不交叉或接触自身。如上所述,给定的多边形始终是凸面。
最后一个数据集后跟一条包含单个零的线。
输出
对于输入中的每个数据集,应输出一行包含离海洋最远点的距离。输出行不应包含空格等额外字符。答案的误差不应大于 0.00001 (10+5)。您可以在小数点后输出任意数量的数字,前提是满足上述精度条件。
题意理解:
有一个凸多边形的小岛,求出岛上离海最远的点到海的距离。
经典的求凸包最大内切圆半径的题。
刘汝佳大白书的例题,经典的做法是平移凸多边形的所有边,通过不断内缩凸多边形,判断是否存在内核(无内核就无内切圆),可以确定最大的半径。
#include<iostream>
#include<cmath>
#include<algorithm>
using namespace std;
const double eps = 1e-6;
const int inf=0x3f3f3f3f;
struct Point{
double x, y;
Point(double x = 0, double y = 0):x(x),y(y){}
}p[205],poly[205];
typedef Point Vector;
Vector operator + (Vector A, Vector B){
return Vector(A.x+B.x, A.y+B.y);
}
Vector operator - (Point A, Point B){
return Vector(A.x-B.x, A.y-B.y);
}
Vector operator * (Vector A, double p){
return Vector(A.x*p, A.y*p);
}
int sgn(double x){
if(fabs(x) < eps)
return 0;
if(x < 0)
return -1;
return 1;
}
double Dot(Vector A, Vector B){
return A.x*B.x + A.y*B.y;
}
double Cross(Vector A, Vector B){
return A.x*B.y-A.y*B.x;
}
double Length(Vector A){
return sqrt(Dot(A, A));
}
Vector Normal(Vector A){//向量A左转90°的单位法向量
double L = Length(A);
return Vector(-A.y/L, A.x/L);
}
struct Line{
Point p;//直线上任意一点
Vector v;//方向向量,它的左边就是对应的半平面
double ang;//极角,即从x轴正半轴旋转到向量v所需要的角(弧度)
Line(){}
Line(Point p, Vector v) : p(p), v(v){
ang = atan2(v.y, v.x);
}
bool operator < (const Line& L) const {//排序用的比较运算符
return ang < L.ang;
}
}L[1005];
//点p在有向直线L的左侧
bool OnLeft(Line L, Point p){
return Cross(L.v,p-L.p)>0;
}
//两直线交点。假定交点唯一存在
Point GetIntersection(Line a, Line b){
Vector u = a.p - b.p;
double t = Cross(b.v, u)/Cross(a.v, b.v);
return a.p + a.v*t;
}
//半平面交的主过程
int HalfplaneIntersection(Line* L, int n, Point* poly){
sort(L, L + n);//按照极角排序
int fst = 0, lst = 0;//双端队列的第一个元素和最后一个元素
Point *P = new Point[n];//p[i] 为 q[i]与q[i + 1]的交点
Line *q = new Line[n];//双端队列
q[fst = lst = 0] = L[0];//初始化为只有一个半平面L[0]
for(int i = 1; i < n; ++i){
while(fst < lst && !OnLeft(L[i], P[lst - 1])) --lst;
while(fst < lst && !OnLeft(L[i], P[fst])) ++fst;
q[++lst] = L[i];
if(sgn(Cross(q[lst].v, q[lst - 1].v)) == 0){
//两向量平行且同向,取内侧一个
--lst;
if(OnLeft(q[lst], L[i].p)) q[lst] = L[i];
}
if(fst < lst)
P[lst - 1] = GetIntersection(q[lst - 1], q[lst]);
}
while(fst < lst && !OnLeft(q[fst], P[lst - 1])) --lst;
//删除无用平面
if(lst - fst <= 1) return 0;//空集
P[lst] = GetIntersection(q[lst], q[fst]);//计算首尾两个半平面的交点
//从deque复制到输出中
int m = 0;
for(int i = fst; i <= lst; ++i) poly[m++] = P[i];
return m;
}
Vector v[200];
int main(){
int n;
while(~scanf("%d",&n)&&n){
for(int i=n-1;i>=0;i--)
scanf("%lf%lf",&p[i].x,&p[i].y);
v[0]=p[n-1]-p[0];
for(int i=1;i<n;i++)
v[i]=p[i-1]-p[i];
// for(int i=0;i<n;i++)
// v[i]=p[(i+1)%n]-p[i];
double l=0,r=20000;
while(r-l>1e-7){
double mid=l+(r-l)/2;
for(int i=0;i<n;i++){
L[i]=Line(p[i]+Normal(v[i])*mid,v[i]);
}
int m=HalfplaneIntersection(L,n,poly);
if(!m) r=mid;
else l=mid;
}
printf("%.6f\n",l);
}
return 0;
}
/*
4
0 0
10000 0
10000 10000
0 10000
3
0 0
10000 0
7000 1000
6
0 40
100 20
250 40
250 70
100 90
0 70
3
0 0
10000 10000
5000 5001
0
*/