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 }
代码君

 

你可能感兴趣的:(ant)