LA 3890 (半平面交) Most Distant Point from the Sea

题意:

给出一个凸n边形,求多边形内部一点使得该点到边的最小距离最大。

分析:

最小值最大可以用二分。

多边形每条边的左边是一个半平面,将这n个半平面向左移动距离x,则将这个凸多边形缩小了。如果这n个半平面交非空,则存在这样距离为x的点,反之则不存在。

半平面交的代码还没有完全理解。

和凸包类似,先对这些半平面进行极角排序。每次新加入的平面可能让队尾的平面变得“无用”,从而需要删除。由于极角序是环形的,所以也可能让队首元素变得“无用”。所以用双端队列来维护。

  1 //#define LOCAL
  2 #include <cstdio>
  3 #include <cstring>
  4 #include <algorithm>
  5 #include <cmath>
  6 #include <vector>
  7 using namespace std;
  8
  9 const double eps = 1e-6;
 10
 11 struct Point
 12 {
 13     double x, y;
 14     Point(double x=0, double y=0):x(x), y(y){}
 15 };
 16 typedef Point Vector;
 17 Point operator + (Point A, Point B) { return Point(A.x+B.x, A.y+B.y); }
 18 Point operator - (Point A, Point B) { return Point(A.x-B.x, A.y-B.y); }
 19 Vector operator * (Vector A, double p) { return Vector(A.x*p, A.y*p); }
 20 Vector operator / (Vector A, double p) { return Vector(A.x/p, A.y/p); }
 21 double Dot(Vector A, Vector B) { return A.x*B.x + A.y*B.y; }
 22 double Cross(Vector A, Vector B) { return A.x*B.y - A.y*B.x; }
 23 double Length(Vector A) { return sqrt(Dot(A, A)); }
 24 Vector Normal(Vector A) { double l = Length(A); return Vector(-A.y/l, A.x/l); }
 25
 26 double PolygonArea(const vector<Point>& p)
 27 {
 28     double ans = 0.0;
 29     int n = p.size();
 30     for(int i = 1; i < n-1; ++i)
 31         ans += Cross(p[i]-p[0], p[i+1]-p[0]);
 32     return ans/2;
 33 }
 34
 35 struct Line
 36 {
 37     Point p;
 38     Vector v;
 39     double ang;
 40     Line() {}
 41     Line(Point p, Vector v):p(p), v(v) { ang = atan2(v.y, v.x); }
 42     bool operator < (const Line& L) const
 43     {
 44         return ang < L.ang;
 45     }
 46 };
 47
 48 bool OnLeft(const Line& L, const Point& p)
 49 { return Cross(L.v, p-L.p) > 0; }
 50
 51 Point GetLineIntersection(const Line& a, const Line& b)
 52 {
 53     Vector u = a.p-b.p;
 54     double t = Cross(b.v, u) / Cross(a.v, b.v);
 55     return a.p + a.v*t;
 56 }
 57
 58 vector<Point> HalfplaneIntersection(vector<Line> L)
 59 {
 60     int n = L.size();
 61     sort(L.begin(), L.end());
 62
 63     int first, last;
 64     vector<Point> p(n);
 65     vector<Line> q(n);
 66     vector<Point> ans;
 67
 68     q[first=last=0] = L[0];
 69     for(int i = 1; i < n; ++i)
 70     {
 71         while(first < last && !OnLeft(L[i], p[last-1])) last--;
 72         while(first < last && !OnLeft(L[i], p[first])) first++;
 73         q[++last] = L[i];
 74         if(fabs(Cross(q[last].v, q[last-1].v)) < eps)    //Èç¹ûÁ½Ö±ÏßƽÐУ¬È¡ÄÚ²àµÄÄǸö
 75         {
 76             last--;
 77             if(OnLeft(q[last], L[i].p)) q[last] = L[i];
 78         }
 79         if(first < last) p[last-1] = GetLineIntersection(q[last-1], q[last]);
 80     }
 81     while(first < last && !OnLeft(q[first], p[last-1])) last--;
 82     if(last - first <= 1)    return ans;
 83     p[last] = GetLineIntersection(q[last], q[first]);
 84
 85     for(int i = first; i <= last; ++i)    ans.push_back(p[i]);
 86     return ans;
 87 }
 88
 89 int main(void)
 90 {
 91     #ifdef LOCAL
 92         freopen("3890in.txt", "r", stdin);
 93     #endif
 94
 95     int n;
 96     while(scanf("%d", &n) == 1 && n)
 97     {
 98         vector<Point> p, v, normal;
 99         int m, x, y;
100         for(int i = 0; i < n; ++i) { scanf("%d%d", &x, &y); p.push_back(Point(x, y)); }
101         if(PolygonArea(p) < 0) reverse(p.begin(), p.end());
102
103         for(int i = 0; i < n; ++i)
104         {
105             v.push_back(p[(i+1)%n] - p[i]);
106             normal.push_back(Normal(v[i]));
107         }
108
109         double left = 0, right = 20000;
110         while(right - left > 5e-7)
111         {
112             vector<Line> L;
113             double mid = (right + left) / 2;
114             for(int i = 0; i < n; ++i) L.push_back(Line(p[i] + normal[i]*mid, v[i]));
115             vector<Point> Poly = HalfplaneIntersection(L);
116             if(Poly.empty())    right = mid;
117             else left = mid;
118         }
119         printf("%.6lf\n", left);
120     }
121
122     return 0;
123 }

代码君

时间: 2024-10-08 22:51:39

LA 3890 (半平面交) Most Distant Point from the Sea的相关文章

LA 2218 (半平面交) Triathlon

题意: 有n个选手,铁人三项有连续的三段,对于每段场地选手i分别以vi, ui 和 wi匀速通过. 对于每个选手,问能否通过调整每种赛道的长度使得他成为冠军(不能并列). 分析: 粗一看,这不像一道计算几何的题目. 假设赛道总长度是1,第一段长x,第二段长y,第三段则是1-x-y 那么可以计算出每个选手完成比赛的时间Ti 对于选手i,若要成为冠军则有Ti < Tj (i ≠ j) 于是就有n-1个不等式,每个不等式都代表一个半平面. 在加上x>0, y>0, 1-x-y>0 这三个

简单几何(半平面交+二分) LA 3890 Most Distant Point from the Sea

题目传送门 题意:凸多边形的小岛在海里,问岛上的点到海最远的距离. 分析:训练指南P279,二分答案,然后整个多边形往内部收缩,如果半平面交非空,那么这些点构成半平面,存在满足的点. /************************************************ * Author :Running_Time * Created Time :2015/11/10 星期二 14:16:17 * File Name :LA_3890.cpp ********************

UVA 3890 Most Distant Point from the Sea(二分法+半平面交)

题目链接:http://acm.hust.edu.cn/vjudge/problem/viewProblem.action?id=11358 [思路] 二分法+半平面交 二分与海边的的距离,由法向量可以得到平移后的各边,半平面交在特定精度判断是否有交集. [代码] 1 #include<cmath> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 using namespace s

POJ3525-Most Distant Point from the Sea(二分+半平面交)

Most Distant Point from the Sea Time Limit: 5000MS   Memory Limit: 65536K Total Submissions: 3955   Accepted: 1847   Special Judge Description The main land of Japan called Honshu is an island surrounded by the sea. In such an island, it is natural t

poj 3525 Most Distant Point from the Sea 半平面交 + 二分

题目来源: http://poj.org/problem?id=3525 分析: 题意:给定一个凸多边形,求多边形中距离边界最远的点到边界的距离. 思路 : 每次将凸多边形每条边往里平移d,判断是否存在核:二分d即可. 多边形边上的点(x , y)往里平移d 后的 坐标: s , e  为向量的 起点和终点, len 为起点和终点的距离, h 为平移的距离 x' = x + dx y' = y + dy dx = ( s.y - e.y ) / len * h ,( 原理 是 利用 三角形的相似

poj3525Most Distant Point from the Sea(半平面交)

链接 求凸多边形内一点距离边最远. 做法:二分+半平面交判定. 二分距离,每次让每条边向内推进d,用半平面交判定一下是否有核. 本想自己写一个向内推进..仔细一看发现自己的平面交模板上自带.. 1 #include <iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 #include<stdlib.h> 6 #include<vector>

POJ 3525 Most Distant Point from the Sea (半平面交向内推进+二分半径)

题目链接 题意 : 给你一个多边形,问你里边能够盛的下的最大的圆的半径是多少. 思路 :先二分半径r,半平面交向内推进r.模板题 1 #include <stdio.h> 2 #include <string.h> 3 #include <iostream> 4 #include <math.h> 5 const double eps = 1e-10 ; 6 7 using namespace std ; 8 9 struct node 10 { 11 do

【POJ 3525】Most Distant Point from the Sea(直线平移、半平面交)

按逆时针顺序给出n个点,求它们组成的多边形的最大内切圆半径. 二分这个半径,将所有直线向多边形中心平移r距离,如果半平面交不存在那么r大了,否则r小了. 平移直线就是对于向量ab,因为是逆时针的,向中心平移就是向向量左手边平移,求出长度为r方向指向向量左手边的向量p,a+p指向b+p就是平移后的向量. 半平面交就是对于每个半平面ax+by+c>0,将当前数组里的点(一开始是所有点)带入,如果满足条件,那么保留该点,否则,先看i-1号点是否满足条件,如果满足,那么将i-1和i点所在直线和直线ax+

poj 3525Most Distant Point from the Sea【二分+半平面交】

相当于多边形内最大圆,二分半径r,然后把每条边内收r,求是否有半平面交(即是否合法) #include<iostream> #include<cstdio> #include<algorithm> #include<cmath> using namespace std; const int N=205; const double eps=1e-6; int n; struct dian { double x,y; dian(double X=0,double