1. 程式人生 > >HDU-4454 Stealing a Cake 計算幾何 三分

HDU-4454 Stealing a Cake 計算幾何 三分

HDU-4454 Stealing a Cake

題意: 給定一個點, 圓和矩形。 求這個點到圓和再從圓到矩形的最短距離之和。
分析: 很明顯這個距離是一個凹函式, 我們要求這個極值點, 這裡用到三分, 標準解法, 要注意的是, 需要分為兩個部分[0, pi]和[pi, 2*pi]。是因為他的函式影象是這樣的。
在這裡插入圖片描述
所以我們要分成兩個部分分別求極值, 然後取最小值即可。
程式碼:

#include <bits/stdc++.h>

using namespace std;

const double pi = acos(-1.0);
const double eps =
1e-8; const double inf = 0x3f3f3f3f; int sgn(double x) { if (fabs(x) < eps) return 0; else if (x < 0) return -1; else return 1; } struct Point { double x, y; Point() {} Point(double _x, double _y) { x = _x; y = _y; } Point operator
+(const Point b) const { return Point(x + b.x, y + b.y); } Point operator-(const Point b) const { return Point(x - b.x, y - b.y); } double operator^(const Point b) const { return x * b.y - y * b.x; } double operator*(const Point b) const
{ return x * b.x + y * b.y; } double distance(Point p) { return hypot(x - p.x, y - p.y); } }; struct Line { Point s, e; Line() {} Line(Point _s, Point _e) { s = _s; e = _e; } double length() { return s.distance(e); } double dispointtoline(Point p) { return fabs((p - s) ^ (e - s)) / length(); } double dispointtoseg(Point p) { if (sgn((p - s) * (e - s)) < 0 || sgn((p - e) * (s - e)) < 0) return min(p.distance(s), p.distance(e)); return dispointtoline(p); } }; Point st, c1, t1, t2; double r; Point getPoint(double angle) { double xx = c1.x + r * cos(angle); double yy = c1.y + r * sin(angle); return Point(xx, yy); } double getdist(Point p) { Line l1(t1, Point(t1.x, t2.y)); Line l2(t1, Point(t2.x, t1.y)); Line l3(t2, Point(t1.x, t2.y)); Line l4(t2, Point(t2.x, t1.y)); double res = inf; res = min(res, l1.dispointtoseg(p)); res = min(res, l2.dispointtoseg(p)); res = min(res, l3.dispointtoseg(p)); res = min(res, l4.dispointtoseg(p)); return res; } double solve() { double l, r, mid, midmid; double ans = inf; Point p1, p2; double dis1, dis2; l = 0, r = pi; while (r - l >= eps) { mid = (l + r) / 2; midmid = (mid + r) / 2; p1 = getPoint(mid); p2 = getPoint(midmid); dis1 = p1.distance(st) + getdist(p1); dis2 = p2.distance(st) + getdist(p2); if (dis1 > dis2) l = mid; else r = midmid; } Point tt = getPoint(l); ans = tt.distance(st) + getdist(tt); l = pi; r = 2 * pi; while (r - l >= eps) { mid = (l + r) / 2; midmid = (mid + r) / 2; p1 = getPoint(mid); p2 = getPoint(midmid); dis1 = p1.distance(st) + getdist(p1); dis2 = p2.distance(st) + getdist(p2); if (dis1 > dis2) l = mid; else r = midmid; } tt = getPoint(l); ans = min(ans, tt.distance(st) + getdist(tt)); return ans; } int main() { while (cin >> st.x >> st.y) { if (sgn(st.x) == 0 && sgn(st.y) == 0) break; cin >> c1.x >> c1.y >> r; cin >> t1.x >> t1.y >> t2.x >> t2.y; printf("%.2f\n", solve()); } return 0; }