4818 Largest Empty Circle on a Segment (几何+二分)

ACM-ICPC Live Archive

  挺水的一道题,直接二分圆的半径即可。1y~

  类似于以前半平面交求核的做法,假设半径已经知道,我们只需要求出线段周围哪些位置是不能放置圆心的即可。这样就转换为圆与直线,直线与直线交的问题了。

  不知道这题能不能SAA过,有空试下。

代码如下:

  1 #include <cmath>
  2 #include <vector>
  3 #include <cstdio>
  4 #include <cstring>
  5 #include <iostream>
  6 #include <algorithm>
  7 
  8 using namespace std;
  9 
 10 const double EPS = 1e-5;
 11 inline int sgn(double x) { return (x > EPS) - (x < -EPS);}
 12 typedef pair<double, double> Point;
 13 #define x first
 14 #define y second
 15 template<class T> T sqr(T x) { return x * x;}
 16 Point operator + (Point a, Point b) { return Point(a.x + b.x, a.y + b.y);}
 17 Point operator - (Point a, Point b) { return Point(a.x - b.x, a.y - b.y);}
 18 Point operator * (Point a, double p) { return Point(a.x * p, a.y * p);}
 19 Point operator / (Point a, double p) { return Point(a.x / p, a.y / p);}
 20 
 21 inline double cross(Point a, Point b) { return a.x * b.y - a.y * b.x;}
 22 inline double dot(Point a, Point b) { return a.x * b.x + a.y * b.y;}
 23 inline double veclen(Point a) { return sqrt(dot(a, a));}
 24 inline Point vecunit(Point a) { return a / veclen(a);}
 25 inline Point normal(Point a) { return Point(-a.y, a.x) / veclen(a);}
 26 
 27 struct Line {
 28     Point s, t;
 29     Line() {}
 30     Line(Point s, Point t) : s(s), t(t) {}
 31     Point vec() { return t - s;}
 32     Point point(double p) { return s + vec() * p;}
 33     Line move(double p) { // + left - right
 34         Point nor = normal(vec());
 35         return Line(s + nor * p, t + nor * p);
 36     }
 37 } ;
 38 
 39 inline bool between(Point o, Point a, Point b) { return sgn(dot(a - o, b - o)) < 0;}
 40 inline bool between(Point a, Line l) { return between(a, l.s, l.t);}
 41 inline Point llint(Line a, Line b) { return a.point(cross(b.vec(), a.s - b.s) / cross(a.vec(), b.vec()));}
 42 
 43 bool clint(Point a, double r, double *sol) {
 44     if (sgn(r - fabs(a.y)) <= 0) return 0;
 45     double d = sqrt(sqr(r) - sqr(a.y));
 46     //cout << "d " << d << endl;
 47     sol[0] = a.x - d;
 48     sol[1] = a.x + d;
 49     return 1;
 50 }
 51 
 52 Line Y0 = Line(Point(0, 0), Point(1, 0));
 53 
 54 double L;
 55 inline void adjust(double &x) { x = max(0.0, min(L, x));}
 56 Point getseg(Line a, double r) {
 57     vector<double> sol;
 58     sol.clear();
 59     double t[2];
 60     if (clint(a.s, r, t)) sol.push_back(t[0]), sol.push_back(t[1]);
 61     if (clint(a.t, r, t)) sol.push_back(t[0]), sol.push_back(t[1]);
 62     Line l1 = a.move(r), l2 = a.move(-r), l3 = Line(l1.s, l2.s), l4 = Line(l1.t, l2.t);
 63     Point p1 = llint(l1, Y0), p2 = llint(l2, Y0), p3 = llint(l3, Y0), p4 = llint(l4, Y0);
 64     if (between(p1, l1)) sol.push_back(p1.x);
 65     if (between(p2, l2)) sol.push_back(p2.x);
 66     if (between(p3, l3)) sol.push_back(p3.x);
 67     if (between(p4, l4)) sol.push_back(p4.x);
 68     if (sol.size() == 0) return Point(-1, -1);
 69     sort(sol.begin(), sol.end());
 70     //cout << "sol ";
 71     //for (int i = 0; i < sol.size(); i++) cout << sol[i] << ' '; cout << endl;
 72     adjust(sol[0]), adjust(sol[sol.size() - 1]);
 73     return Point(sol[0], sol[sol.size() - 1]);
 74 }
 75 
 76 const int N = 2222;
 77 typedef pair<double, int> Event;
 78 Line l[N];
 79 int n;
 80 
 81 bool test(double r) {
 82     vector<Event> ev;
 83     ev.clear();
 84     for (int i = 0; i < n; i++) {
 85         Point tmp = getseg(l[i], r);
 86         if (tmp.x < 0 || tmp.y < 0) continue;
 87         //cout << tmp.x << '~' << tmp.y << endl;
 88         ev.push_back(Event(tmp.x, 1));
 89         ev.push_back(Event(tmp.y, -1));
 90     }
 91     sort(ev.begin(), ev.end());
 92     //cout << r << endl;
 93     //for (int i = 0; i < ev.size(); i++) cout << ev[i].x << '&' << ev[i].y << ' '; cout << endl;
 94     double last = 0;
 95     int cnt = 0, sz = ev.size();
 96     for (int i = 0; i < sz; i++) {
 97         if (ev[i].y == 1) {
 98             if (cnt == 0 && sgn(ev[i].x - last) > 0) return 1;
 99             cnt++;
100         } else {
101             if (cnt == 1) last = ev[i].x;
102             cnt--;
103         }
104     }
105     return sgn(L - last) > 0;
106 }
107 
108 int main() {
109     //freopen("in", "r", stdin);
110     int T;
111     cin >> T;
112     while (T-- && cin >> n >> L) {
113         for (int i = 0; i < n; i++) cin >> l[i].s.x >> l[i].s.y >> l[i].t.x >> l[i].t.y;
114         double lp = 0, rp = 222222, mp;
115         while (rp - lp > EPS) {
116             mp = (lp + rp) / 2;
117             if (test(mp)) lp = mp;
118             else rp = mp;
119         }
120         //puts("~~~~~~~~~~~~~~~~~~~~~~~~");
121         //test(2.118);
122         printf("%.3f
", mp);
123     }
124     return 0;
125 }
View Code

——written by Lyon

原文地址:https://www.cnblogs.com/LyonLys/p/LA_4818_Lyon.html