题意:求一个凸多边形中一点到边的最大距离。
思路:转换成在多边形内部,到每边距离为d的直线所围成的内多边形是否存在。也就是,二分距离+半平面交。
1 #include<cstdio> 2 #include<cmath> 3 #include<cstring> 4 #include<algorithm> 5 #include<iostream> 6 #include<memory.h> 7 #include<cstdlib> 8 #include<vector> 9 #define clc(a,b) memset(a,b,sizeof(a)) 10 #define LL long long int 11 #define up(i,x,y) for(i=x;i<=y;i++) 12 #define w(a) while(a) 13 const double inf=0x3f3f3f3f; 14 const int N = 4010; 15 const double eps = 5*1e-13; 16 const double PI = acos(-1.0); 17 using namespace std; 18 19 struct Point 20 { 21 double x, y; 22 Point(double x=0, double y=0):x(x),y(y) { } 23 }; 24 25 typedef Point Vector; 26 27 Vector operator + (const Vector& A, const Vector& B) 28 { 29 return Vector(A.x+B.x, A.y+B.y); 30 } 31 Vector operator - (const Point& A, const Point& B) 32 { 33 return Vector(A.x-B.x, A.y-B.y); 34 } 35 Vector operator * (const Vector& A, double p) 36 { 37 return Vector(A.x*p, A.y*p); 38 } 39 double Dot(const Vector& A, const Vector& B) 40 { 41 return A.x*B.x + A.y*B.y; 42 } 43 double Cross(const Vector& A, const Vector& B) 44 { 45 return A.x*B.y - A.y*B.x; 46 } 47 double Length(const Vector& A) 48 { 49 return sqrt(Dot(A, A)); 50 } 51 Vector Normal(const Vector& A) 52 { 53 double L = Length(A); 54 return Vector(-A.y/L, A.x/L); 55 } 56 57 double PolygonArea(vector<Point> p) 58 { 59 int n = p.size(); 60 double area = 0; 61 for(int i = 1; i < n-1; i++) 62 area += Cross(p[i]-p[0], p[i+1]-p[0]); 63 return area/2; 64 } 65 66 // 有向直线。它的左边就是对应的半平面 67 struct Line 68 { 69 Point P; // 直线上任意一点 70 Vector v; // 方向向量 71 double ang; // 极角,即从x正半轴旋转到向量v所需要的角(弧度) 72 Line() {} 73 Line(Point P, Vector v):P(P),v(v) 74 { 75 ang = atan2(v.y, v.x); 76 } 77 bool operator < (const Line& L) const 78 { 79 return ang < L.ang; 80 } 81 }; 82 83 // 点p在有向直线L的左边(线上不算) 84 bool OnLeft(const Line& L, const Point& p) 85 { 86 return Cross(L.v, p-L.P) > 0; 87 } 88 89 // 二直线交点,假定交点惟一存在 90 Point GetLineIntersection(const Line& a, const Line& b) 91 { 92 Vector u = a.P-b.P; 93 double t = Cross(b.v, u) / Cross(a.v, b.v); 94 return a.P+a.v*t; 95 } 96 97 const double INF = 1e8; 98 99 // 半平面交主过程 100 vector<Point> HalfplaneIntersection(vector<Line> L) 101 { 102 int n = L.size(); 103 sort(L.begin(), L.end()); // 按极角排序 104 105 int first, last; // 双端队列的第一个元素和最后一个元素的下标 106 vector<Point> p(n); // p[i]为q[i]和q[i+1]的交点 107 vector<Line> q(n); // 双端队列 108 vector<Point> ans; // 结果 109 110 q[first=last=0] = L[0]; // 双端队列初始化为只有一个半平面L[0] 111 for(int i = 1; i < n; i++) 112 { 113 while(first < last && !OnLeft(L[i], p[last-1])) last--; 114 while(first < last && !OnLeft(L[i], p[first])) first++; 115 q[++last] = L[i]; 116 if(fabs(Cross(q[last].v, q[last-1].v)) < eps) // 两向量平行且同向,取内侧的一个 117 { 118 last--; 119 if(OnLeft(q[last], L[i].P)) q[last] = L[i]; 120 } 121 if(first < last) p[last-1] = GetLineIntersection(q[last-1], q[last]); 122 } 123 while(first < last && !OnLeft(q[first], p[last-1])) last--; // 删除无用平面 124 if(last - first <= 1) return ans; // 空集 125 p[last] = GetLineIntersection(q[last], q[first]); // 计算首尾两个半平面的交点 126 127 // 从deque复制到输出中 128 for(int i = first; i <= last; i++) ans.push_back(p[i]); 129 return ans; 130 } 131 132 int main() 133 { 134 int n; 135 while(scanf("%d", &n) == 1 && n) 136 { 137 vector<Vector> p, v, normal; 138 int m, x, y; 139 for(int i = 0; i < n; i++) 140 { 141 scanf("%d%d", &x, &y); 142 p.push_back(Point(x,y)); 143 } 144 if(PolygonArea(p) < 0) reverse(p.begin(), p.end()); 145 146 for(int i = 0; i < n; i++) 147 { 148 v.push_back(p[(i+1)%n]-p[i]); 149 normal.push_back(Normal(v[i])); 150 } 151 152 double left = 0, right = 20000; 153 while(right-left > 1e-6) 154 { 155 vector<Line> L; 156 double mid = left+(right-left)/2; 157 for(int i = 0; i < n; i++) L.push_back(Line(p[i]+normal[i]*mid, v[i]));//平移直线 158 vector<Point> poly = HalfplaneIntersection(L); 159 if(poly.empty()) right = mid; 160 else left = mid; 161 } 162 printf("%.6lf\n", left); 163 } 164 return 0; 165 }
时间: 2024-11-08 17:30:27