我们可以知道,当这个单位圆可以覆盖到最多的点的时候,必定最少有两个点位于这个圆的圆周上,于是就有网上众多的O(N^3)的枚举两个在圆上的点的暴搜做法。
然而这题是可以用圆交来做的。
我们以一条鱼的位置作为圆心,半径为1的圆的周围随便找一个点都能把这条鱼抓到。这时,我们可以做出很多个这样的圆,半径都为1。
然后,求一下这些圆的交集,叠起来的最高层数就是最多能获得的鱼的数目。
这里的圆交不需要实现求面积这部分,于是只需要离散一下交点就行了。
1y。
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
1 #include <cstdio> 2 #include <cstring> 3 #include <iostream> 4 #include <algorithm> 5 #include <iomanip> 6 #include <cmath> 7 8 using namespace std; 9 10 const double EPS = 1e-8; 11 const double PI = acos(-1.0); 12 inline int sgn(double x) { return (x > EPS) - (x < -EPS);} 13 template<class T> T sqr(T x) { return x * x;} 14 typedef pair<double, double> Point; 15 #define x first 16 #define y second 17 18 Point operator + (Point a, Point b) { return Point(a.x + b.x, a.y + b.y);} 19 Point operator - (Point a, Point b) { return Point(a.x - b.x, a.y - b.y);} 20 Point operator * (Point a, double p) { return Point(a.x * p, a.y * p);} 21 Point operator * (double p, Point a) { return Point(a.x * p, a.y * p);} 22 Point operator / (Point a, double p) { return Point(a.x / p, a.y / p);} 23 24 inline double cross(Point a, Point b) { return a.x * b.y - a.y * b.x;} 25 inline double dot(Point a, Point b) { return a.x * b.x + a.y * b.y;} 26 inline double veclen(Point a) { return sqrt(dot(a, a));} 27 inline double angle(Point a) { return atan2(a.y, a.x);} 28 inline Point vecunit(Point a) { return a / veclen(a);} 29 inline Point normal(Point a) { return Point(-a.y, a.x) / veclen(a);} 30 31 struct Line { 32 Point s, t; 33 Line() {} 34 Line(Point s, Point t) : s(s), t(t) {} 35 Point vec() { return t - s;} 36 Point point(double p) { return s + vec() * p;} 37 } ; 38 inline Point llint(Line a, Line b) { return a.point(cross(b.vec(), a.s - b.s) / cross(a.vec(), b.vec()));} 39 40 struct Circle { 41 Point c; 42 double r; 43 Circle() {} 44 Circle(Point c, double r) : c(c), r(r) {} 45 Point point(double p) { return c + r * Point(cos(p), sin(p));} 46 bool in(Point p) { return sgn(veclen(p - c) - r) < 0;} 47 } ; 48 49 const double R = 1000.0; 50 const int N = 333; 51 int n; 52 Circle cir[N]; 53 54 void input() { 55 cin >> n; 56 for (int i = 0; i < n; i++) { 57 cin >> cir[i].c.x >> cir[i].c.y; 58 cir[i].c = cir[i].c * R; 59 cir[i].r = R; 60 } 61 } 62 63 bool ccint(int _a, int _b, double *sol) { 64 Circle a = cir[_a], b = cir[_b]; 65 double d = veclen(a.c - b.c), dr = fabs(a.r - b.r); 66 if (sgn(d - a.r - b.r) > 0) return 0; 67 if (sgn(dr - d) >= 0) { 68 if (a.r < b.r || sgn(a.r - b.r) == 0 && _a < _b) { 69 sol[0] = -PI; 70 sol[1] = PI; 71 return 1; 72 } 73 return 0; 74 } 75 double ang = angle(b.c - a.c); 76 double da = acos(fabs(sqr(a.r) + sqr(d) - sqr(b.r)) / (2 * a.r * d)); 77 sol[0] = ang - da; 78 sol[1] = ang + da; 79 return 1; 80 } 81 82 typedef pair<double, int> Event; 83 Event ev[N << 1]; 84 bool cmp(Event a, Event b) { 85 if (sgn(a.x - b.x)) return a.x < b.x; 86 return a.y > b.y; 87 } 88 89 int cal(int id) { 90 int tt = 0; 91 double _[2]; 92 for (int i = 0; i < n; i++) { 93 if (i == id) continue; 94 if (ccint(id, i, _)) { 95 if (_[0] < -PI) { 96 ev[tt++] = Event(_[0] + 2 * PI, 1); 97 ev[tt++] = Event(PI, -1); 98 ev[tt++] = Event(-PI, 1); 99 ev[tt++] = Event(_[1], -1); 100 } else if (_[1] > PI) { 101 ev[tt++] = Event(_[0], 1); 102 ev[tt++] = Event(PI, -1); 103 ev[tt++] = Event(-PI, 1); 104 ev[tt++] = Event(_[1] - 2 * PI, -1); 105 } else { 106 ev[tt++] = Event(_[0], 1); 107 ev[tt++] = Event(_[1], -1); 108 } 109 } 110 } 111 int cnt = 1, mx = 1; 112 sort(ev, ev + tt, cmp); 113 for (int i = 0; i < tt; i++) { 114 cnt += ev[i].y; 115 mx = max(mx, cnt); 116 } 117 return mx; 118 } 119 120 int work() { 121 int mx = 0; 122 for (int i = 0; i < n; i++) mx = max(mx, cal(i)); 123 return mx; 124 } 125 126 int main() { 127 //freopen("in", "r", stdin); 128 ios::sync_with_stdio(0); 129 cout << setiosflags(ios::fixed) << setprecision(5); 130 int _; 131 cin >> _; 132 while (_--) { 133 input(); 134 cout << work() << endl; 135 } 136 return 0; 137 }
——written by Lyon