传送门:https://284914869.github.io/AEoj/559.html
题目简述:
n个实心圆,两两没有交集,在第一个圆上找一个点,使得它到另外一个圆上某个点的最短距离的最小值尽量大,两个点之间的最短距离是指连接两个点且中途不进入任何一个实心圆内部的路径的长度的最小值。
二分答案:
很显然,这题跟二分答案有关。
思路:
我们先考虑,如果第一个圆上的点确定了下来,它到别的所有的圆的距离的最小值。
The First Case:
The Second Case:
图中蓝色线是最短的路径。
当然还有第三种情况,就是路径过程中与别的圆相交了。不过这样肯定不是所有的路中最短的,所以可以忽略这种情况。
那么接下来考虑二分答案。
对于当前二分到的mid,
检查最终答案是否>=mid。
即是否存在最短路径都>=mid的点。
那么一个很简单的思路就出来了,对于每个圆,起点到它的最短路>=mid,可以确定起点一定不在圆上的某条弧上。
同样分两种情况,求出所有的起点位置限制。最后对这些位置限制(弧)排个序,判断合不合法即可。
题外话:
为了图方便,打算用余弦定理求位置限制,结果把公式背错了,对着样例调试了好久?
代码:
1 #include <cmath> 2 #include <cstdio> 3 #include <string> 4 #include <vector> 5 #include <cstring> 6 #include <iostream> 7 #include <algorithm> 8 using namespace std; 9 #define _CLASSNAME_ CircusTents 10 #define _METHODNAME_ findMaximumDistance 11 #define _RC_ double 12 #define _METHODPARMS_ vector <int> x, vector <int> y, vector <int> r 13 #define ref(i,x,y)for(int i=x;i<=y;++i) 14 #define def(i,x,y)for(int i=x;i>=y;--i) 15 typedef long double LD; 16 const int N = 51; 17 const LD pi = acos(-1); 18 int n; 19 struct xint { int x, y, r; }s[N]; 20 struct yint { LD op, ed; }S[N]; 21 bool cmp(yint a, yint b) { return a.op < b.op; } 22 bool check(LD ss) { 23 ref(i, 2, n) { 24 LD _min = sqrt(s[i].x*s[i].x + s[i].y*s[i].y) - s[1].r; 25 LD _max = sqrt(s[i].x*s[i].x + s[i].y*s[i].y - s[1].r*s[1].r); 26 LD _dis = s[i].r + ss; 27 if (_dis < _min) { 28 S[i].op = 0, S[i].ed = 0; continue; 29 } 30 LD b = atan2(s[i].y, s[i].x); if (b < 0)b = 2 * pi + b; 31 if (_dis > _max) { 32 LD a = (_dis - _max) / s[1].r + acos(s[1].r / sqrt(s[i].x*s[i].x + s[i].y*s[i].y)); 33 if (a > pi)S[i].op = 0, S[i].ed = 2 * pi; 34 else S[i].op = b - a, S[i].ed = b + a; 35 } 36 else { 37 LD dis2 = s[i].x*s[i].x + s[i].y*s[i].y; 38 //s[1].r*s[1].r + dis2 - 2 * s[1].r*sqrt(dis2)* cos(alpha) = _dis*_dis; 39 LD a = acos((s[1].r*s[1].r + dis2 - _dis*_dis) / 2 / s[1].r / sqrt(dis2)); 40 S[i].op = b - a, S[i].ed = b + a; 41 } 42 if (S[i].ed > 2 * pi)S[i].op -= 2 * pi, S[i].ed -= 2 * pi; 43 } 44 LD LL = 0, RR = 2 * pi; 45 sort(S + 2, S + n + 1, cmp); 46 ref(i, 2, n) { 47 if (S[i].op < 0)LL = max(LL, S[i].ed), RR = min(RR, S[i].op + 2 * pi); 48 else { 49 if (LL < S[i].op)return 1; 50 if (S[i].ed > LL)LL = S[i].ed; 51 } 52 if (LL >= RR)return 0; 53 } 54 return 1; 55 } 56 LD work() { 57 LD L = -1e6, R = 1e6; 58 ref(times, 1, 50) { 59 LD mid = (L + R) / 2; 60 if (check(mid))L = mid; else R = mid; 61 } 62 return L; 63 } 64 class _CLASSNAME_ { 65 public: 66 _RC_ _METHODNAME_(_METHODPARMS_) 67 { 68 n = x.size(); 69 ref(i, 1, n)s[i].x = x[i - 1], s[i].y = y[i - 1], s[i].r = r[i - 1]; 70 ref(i, 2, n)s[i].x -= s[1].x, s[i].y -= s[1].y; s[1].x = s[1].y = 0; 71 return _RC_(work()); 72 } 73 74 // BEGIN CUT HERE 75 public: 76 void run_test(int Case) { if ((Case == -1) || (Case == 0)) test_case_0(); if ((Case == -1) || (Case == 1)) test_case_1(); if ((Case == -1) || (Case == 2)) test_case_2(); if ((Case == -1) || (Case == 3)) test_case_3(); if ((Case == -1) || (Case == 4)) test_case_4(); } 77 private: 78 template <typename T> string print_array(const vector<T> &V) { ostringstream os; os << "{ "; for (typename vector<T>::const_iterator iter = V.begin(); iter != V.end(); ++iter) os << '\"' << *iter << "\","; os << " }"; return os.str(); } 79 void verify_case(int Case, const double &Expected, const double &Received) { cerr << "Test Case #" << Case << "..."; if (Expected == Received) cerr << "PASSED" << endl; else { cerr << "FAILED" << endl; cerr << "\tExpected: \"" << Expected << '\"' << endl; cerr << "\tReceived: \"" << Received << '\"' << endl; } } 80 void test_case_0() { int Arr0[] = { 0,3 }; vector <int> Arg0(Arr0, Arr0 + (sizeof(Arr0) / sizeof(Arr0[0]))); int Arr1[] = { 0,0 }; vector <int> Arg1(Arr1, Arr1 + (sizeof(Arr1) / sizeof(Arr1[0]))); int Arr2[] = { 1,1 }; vector <int> Arg2(Arr2, Arr2 + (sizeof(Arr2) / sizeof(Arr2[0]))); double Arg3 = 3.7390603609952078; verify_case(0, Arg3, findMaximumDistance(Arg0, Arg1, Arg2)); } 81 void test_case_1() { int Arr0[] = { 0,3,-3,3,-3 }; vector <int> Arg0(Arr0, Arr0 + (sizeof(Arr0) / sizeof(Arr0[0]))); int Arr1[] = { 0,3,3,-3,-3 }; vector <int> Arg1(Arr1, Arr1 + (sizeof(Arr1) / sizeof(Arr1[0]))); int Arr2[] = { 1,1,1,1,1 }; vector <int> Arg2(Arr2, Arr2 + (sizeof(Arr2) / sizeof(Arr2[0]))); double Arg3 = 2.6055512754639887; verify_case(1, Arg3, findMaximumDistance(Arg0, Arg1, Arg2)); } 82 void test_case_2() { int Arr0[] = { 3,7,7,7,3 }; vector <int> Arg0(Arr0, Arr0 + (sizeof(Arr0) / sizeof(Arr0[0]))); int Arr1[] = { 4,6,1,-3,0 }; vector <int> Arg1(Arr1, Arr1 + (sizeof(Arr1) / sizeof(Arr1[0]))); int Arr2[] = { 2,2,2,1,1 }; vector <int> Arg2(Arr2, Arr2 + (sizeof(Arr2) / sizeof(Arr2[0]))); double Arg3 = 4.3264459099620725; verify_case(2, Arg3, findMaximumDistance(Arg0, Arg1, Arg2)); } 83 void test_case_3() { int Arr0[] = { 10,-1 }; vector <int> Arg0(Arr0, Arr0 + (sizeof(Arr0) / sizeof(Arr0[0]))); int Arr1[] = { 0,0 }; vector <int> Arg1(Arr1, Arr1 + (sizeof(Arr1) / sizeof(Arr1[0]))); int Arr2[] = { 8,2 }; vector <int> Arg2(Arr2, Arr2 + (sizeof(Arr2) / sizeof(Arr2[0]))); double Arg3 = 24.63092458664212; verify_case(3, Arg3, findMaximumDistance(Arg0, Arg1, Arg2)); } 84 void test_case_4() { int Arr0[] = { 0,4,-4 }; vector <int> Arg0(Arr0, Arr0 + (sizeof(Arr0) / sizeof(Arr0[0]))); int Arr1[] = { 0,4,-4 }; vector <int> Arg1(Arr1, Arr1 + (sizeof(Arr1) / sizeof(Arr1[0]))); int Arr2[] = { 1,1,1 }; vector <int> Arg2(Arr2, Arr2 + (sizeof(Arr2) / sizeof(Arr2[0]))); double Arg3 = 4.745474963675133; verify_case(4, Arg3, findMaximumDistance(Arg0, Arg1, Arg2)); } 85 // END CUT HERE 86 87 }; 88 89 // BEGIN CUT HERE 90 int main() 91 { 92 /* 93 {3, 7, 7, 7, 3} 94 {4, 6, 1, -3, 0} 95 {2, 2, 2, 1, 1} 96 */ 97 CircusTents ___test; 98 ___test.run_test(-1); 99 getchar(); 100 return 0; 101 } 102 // END CUT HERE