题意:有一堆兔子,还有一个r为半径的圆,要求找到最大集合满足这个集合里的兔子两两连边的直线不经过圆。
思路:发现如果有两个点之间连边不经过圆,那么他们到圆的切线会构成一段区间,那么这两个点的区间一定会有交集,形如s0 s1 e0 e1
同样的,如果是n个点,那就是s0 s1 s2..sn e0 e1 e2.. en
因此,我们枚举那个起始点,然后对于其他点我们按照s排序,对于e做最长上升子序列即可。时间复杂度O(n^2 logn)
1 #include <cstdio> 2 #include <algorithm> 3 #include <cmath> 4 #include <vector> 5 const double pi = 3.14159265358979324; 6 double th1[2000], th2[2000], b[2000], x[2000], y[2000]; 7 std::pair<std::pair<double, double>, int> a[2000]; 8 int t[2001], t2[2001], f[2001], n; 9 std::vector<int> ansv; 10 double r; 11 int main() { 12 freopen("crazy.in", "r", stdin); 13 freopen("crazy.out", "w", stdout); 14 scanf("%d%lf", &n, &r); 15 for (int i = 0; i < n; i++) { 16 scanf("%lf%lf", &x[i], &y[i]); 17 double th = atan2(y[i], x[i]); 18 double dth = acos(r / sqrt(x[i] * x[i] + y[i] * y[i])); 19 th1[i] = th + dth; if (th1[i] > pi) th1[i] -= 2*pi; 20 th2[i] = th - dth; if (th2[i] <= -pi) th2[i] += 2*pi; 21 if (th1[i] > th2[i]) std::swap(th1[i], th2[i]); 22 } 23 int ans = 1; 24 ansv.push_back(0); 25 for (int i = 0; i < n; i++) { 26 int l = 0, ans2 = -1; 27 for (int j = 0; j < n; j++) 28 if (i != j && (th1[j] < th1[i] || th1[j] > th2[i] || th2[j] < th1[i] || th2[j] > th2[i]) 29 && (th1[j] > th1[i] && th1[j] < th2[i] || th2[j] > th1[i] && th2[j] < th2[i])) { 30 if (th1[j] > th1[i] && th1[j] < th2[i]) { 31 a[l].first.first = th1[j] - th1[i]; 32 a[l].first.second = th2[j] - th2[i]; 33 } else { 34 a[l].first.first = th2[j] - th1[i]; 35 a[l].first.second = th1[j] - th2[i]; 36 } 37 if (a[l].first.second < 0) a[l].first.second += 2*pi; 38 a[l].second = j; 39 l++; 40 } 41 std::sort(a, a + l); 42 for (int j = 0; j < l; j++) b[j] = a[j].first.second; 43 std::sort(b, b + l); 44 for (int j = 1; j <= l; j++) t[j] = 0; 45 for (int j = 0; j < l; j++) { 46 int p = std::lower_bound(b, b + l, a[j].first.second) - b + 1; 47 int v = 0, v2 = -1; 48 for (int k = p; k; k -= k&-k) 49 if (t[k] > v) v = t[k], v2 = t2[k]; 50 v++; 51 f[a[j].second] = v2; 52 if (v+1 > ans) ans = v+1, ans2 = a[j].second; 53 for (int k = p; k <= l; k += k&-k) 54 if (t[k] < v) t[k] = v, t2[k] = a[j].second; 55 } 56 if (ans2 != -1) { 57 ansv.clear(); 58 while (ans2 != -1) 59 ansv.push_back(ans2), ans2 = f[ans2]; 60 ansv.push_back(i); 61 } 62 } 63 printf("%d ", ans); 64 return 0; 65 }