给出N个圆Ci , 两个点 s ,t。
如果点在某个圆上面的话,可以转动一个圆,使得点随着圆转动。问能不能从s转到t。
我们注意到几个“可达”的情况:
1、如果A.B两点都在某圆上,并且距离圆心距离相等,那么可达。
2、初始情况。
对于下图情况,对于点S在圆O上
那么S在圆O上面可达的区间就是一个圆(以黑色标出)
此时又来了一个另外的圆O',与两个圆相交,因为S只能在黑色轨迹上运动,隐去绿色的圆
我们可以看到此时黑色的圆和绿色的圆O' 就有一定的交汇,那么点S在圆O'可达的区间如下图的黄色部分所示
这样我们就解决了最初始的情况——对于一个点能达到相邻圆的范围。
3、圆中可达部分
首先我们能很容易地想到就是,中间过程就是把每个圆分解成了一个一个圆环,表示S点在某圆之中的可达区间。如下图
于是我们就要做的是dfs不停求出来一个圆环组 和另一个圆相交的面积圆环,通过dfs对于每个圆维护一个vector< pair<L , R> > 代表半径[L , R] 是一个圆环。
4、圆之间的转移
1)假设在圆O中可达区间是
中间淡紫色还是蓝色的部分是可达的部分
2)来了一个圆Q,隐去不要的部分
3)我们可以很清晰第看出来,可达的部分是如下图所示的绿色部分
于是乎用外围的R就可以啦~
4)一种特殊要考虑的情况,在这种情况下第二个圆完全可达
5、结果
很简单,如果说点t在某个可达圆环组上或者圆环组内那么就是可达的。
1、见Data 11 , 需要很明确距离用long double 来保存。。真是贱啊。。。
2、同心圆不可消除T_T
3、精度判断 dblcmp
4、圆之间的转换 dfs 内3部分:整理先前结果、查询当前所在区间、圆间转换
const int N = 70; namespace Geo{ #define typec long double const typec eps=1e-14; int dblcmp(double d){ if (fabs(d)<eps)return 0; return d>eps?1:-1; } int sgn(double a) {return a<-eps?-1:a>eps;} inline double sqr(double x){return x*x;} struct Point2D{ typec x,y; Point2D(){} Point2D(typec _x,typec _y):x(_x),y(_y){}; void input(){ scanf("%lf%lf",&x,&y); } bool operator==(Point2D a)const{ return dblcmp(a.x-x)==0&&dblcmp(a.y-y)==0; } bool operator != (Point2D a) const{ return ! ((*this) == a); } bool operator<(Point2D a)const{ return dblcmp(a.x-x)==0?dblcmp(y-a.y)<0:x<a.x; } typec len(){ return hypot(x,y); } typec len2(){ return x*x+y*y; } Point2D operator + (const Point2D &A) const{ return Point2D(x + A.x , y + A.y); } Point2D operator - (const Point2D &A) const{ return Point2D(x - A.x , y - A.y); } Point2D operator * (const typec _x) const{ return Point2D(x * _x , y * _x); } typec operator * (const Point2D &A) const{ return x * A.x + y * A.y; } typec operator ^ (const Point2D &A) const{ return x * A.y - y * A.x; } Point2D operator / (const typec _p) const{ return Point2D(x / _p , y / _p); } typec distance(Point2D p){ return sqrt(sqr((long double)x-p.x) + sqr((long double)y-p.y)); } typec distance2(Point2D p){ return (sqr((long double)x-p.x) + sqr((long double)y-p.y)); } void output(){ printf("( %.15lf , %.15lf )\n" , x , y); } Point2D add(Point2D p){ return Point2D(x+p.x,y+p.y); } Point2D sub(Point2D p){ return Point2D(x-p.x,y-p.y); } Point2D mul(typec b){ return Point2D(x*b,y*b); } Point2D div(typec b){ return Point2D(x/b,y/b); } typec dot(Point2D p){ return x*p.x+y*p.y; } typec det(Point2D p){ return x*p.y-y*p.x; } typec rad(Point2D a,Point2D b){ Point2D p=*this; return fabs(atan2(fabs(a.sub(p).det(b.sub(p))),a.sub(p).dot(b.sub(p)))); } Point2D trunc(typec r){ typec l=len(); if (!dblcmp(l))return *this; r/=l; return Point2D(x*r,y*r); } Point2D rotleft(){ return Point2D(-y,x); } Point2D rotright(){ return Point2D(y,-x); } Point2D rotate(Point2D p,typec angle)//ÈÆµãpÄæÊ±ÕëÐýתangle½Ç¶È { Point2D v=this->sub(p); typec c=cos(angle),s=sin(angle); return Point2D(p.x+v.x*c-v.y*s,p.y+v.x*s+v.y*c); } }; typec cross(Point2D a,Point2D b,Point2D c){ return (b.sub(a)).det(c.sub(a)); } }using namespace Geo; struct Circle{ Point2D O; double r; bool operator < (const Circle & A) const{ if (O != A.O) return O == A.O; return dblcmp(r - A.r) < 0; } bool operator == (const Circle & A) const{ return O == A.O; } }c[N]; Point2D s , t; vector < pair<double , double> > vis[N]; class CandyOnDisk { public: int n; bool dfs(int now , double L , double R){ checkMin(R , c[now].r); if (dblcmp(L - R) > 0) return false; //No intersection checkMin(L , c[now].r); REP_C(i , SZ(vis[now])) if (dblcmp(L - vis[now][i].fi) >= 0 && dblcmp(R - vis[now][i].se) <=0) // All the sub-answers have been searched. return false; vis[now].PB( MP(L , R) ); sort(ALL(vis[now])); vector< pair<double , double> > temp; temp.clear(); double l = -INFF , r = INFF; REP_C(i , SZ(vis[now])){ // Combine the areas that have intersection. Resize the set vis if (dblcmp(vis[now][i].fi - r) <= 0) checkMax(r , vis[now][i].se); else{ if (dblcmp(l - r) <= 0) temp.PB( MP(l , r) ); l = vis[now][i].fi; r = vis[now][i].se; } } if (dblcmp(l - r) <= 0) temp.PB(MP(l , r)); REP(i , SZ(vis[now])) // Find the interval that include [L , R] if (dblcmp(vis[now][i].fi - L) <= 0 && dblcmp(R - vis[now][i].se) <= 0){ L = vis[now][i].fi; R = vis[now][i].se; break; } if (dblcmp(sqr(L) - c[now].O.distance2(t)) <= 0 && dblcmp(c[now].O.distance2(t) - sqr(R)) <= 0) return true; bool res = false; REP(i , n){ if (i == now) continue; double d = c[i].O.distance(c[now].O); if( dblcmp(d) <= 0) res |= dfs(i , L , R); else if (dblcmp(d - R) <= 0) res |= dfs(i , 0 , c[i].r); else if (dblcmp(d - R) >= 0) res |= dfs(i , d - R , c[i].r); } return res; } vector<int> x , y , r; string ableToAchieve(vector <int> X, vector <int> Y, vector <int> R, int sx, int sy, int tx, int ty) { n = SZ(X); x = X , y = Y , r = R; REP(i , n){ c[i].O.x = x[i]; c[i].O.y = y[i]; c[i].r = r[i]; } s.x = sx; s.y = sy; t.x = tx; t.y = ty; if (s == t) return "YES"; REP(i , n) vis[i].clear(); REP(i , n) if (dblcmp(s.distance(c[i].O) - c[i].r) <= 0) if (dfs(i , s.distance(c[i].O) , s.distance(c[i].O))) return "YES"; return "NO"; } }; // BEGIN CUT HERE namespace moj_harness { int run_test_case(int); void run_test(int casenum = -1, bool quiet = false) { if (casenum != -1) { if (run_test_case(casenum) == -1 && !quiet) { cerr << "Illegal input! Test case " << casenum << " does not exist." << endl; } return; } int correct = 0, total = 0; for (int i=0;; ++i) { int x = run_test_case(i); if (x == -1) { if (i >= 100) break; continue; } correct += x; ++total; } if (total == 0) { cerr << "No test cases run." << endl; } else if (correct < total) { cerr << "Some cases FAILED (passed " << correct << " of " << total << ")." << endl; } else { cerr << "All " << total << " tests passed!" << endl; } } int verify_case(int casenum, const string &expected, const string &received, clock_t elapsed) { cerr << "Example " << casenum << "... "; string verdict; vector<string> info; char buf[100]; if (elapsed > CLOCKS_PER_SEC / 200) { sprintf(buf, "time %.2fs", elapsed * (1.0/CLOCKS_PER_SEC)); info.push_back(buf); } if (expected == received) { verdict = "PASSED"; } else { verdict = "FAILED"; } cerr << verdict; if (!info.empty()) { cerr << " ("; for (int i=0; i<(int)info.size(); ++i) { if (i > 0) cerr << ", "; cerr << info[i]; } cerr << ")"; } cerr << endl; if (verdict == "FAILED") { cerr << " Expected: \"" << expected << "\"" << endl; cerr << " Received: \"" << received << "\"" << endl; } return verdict == "PASSED"; } int run_test_case(int casenum) { switch (casenum) { case 0: { int x[] = {0, 4}; int y[] = {0, 0}; int r[] = {3, 3}; int sx = -1; int sy = -2; int tx = 6; int ty = 1; string expected__ = "YES"; clock_t start__ = clock(); string received__ = CandyOnDisk().ableToAchieve(vector <int>(x, x + (sizeof x / sizeof x[0])), vector <int>(y, y + (sizeof y / sizeof y[0])), vector <int>(r, r + (sizeof r / sizeof r[0])), sx, sy, tx, ty); return verify_case(casenum, expected__, received__, clock()-start__); } case 1: { int x[] = {0, 3}; int y[] = {0, 0}; int r[] = {5, 3}; int sx = -4; int sy = 0; int tx = -2; int ty = 0; string expected__ = "YES"; clock_t start__ = clock(); string received__ = CandyOnDisk().ableToAchieve(vector <int>(x, x + (sizeof x / sizeof x[0])), vector <int>(y, y + (sizeof y / sizeof y[0])), vector <int>(r, r + (sizeof r / sizeof r[0])), sx, sy, tx, ty); return verify_case(casenum, expected__, received__, clock()-start__); } case 2: { int x[] = {0}; int y[] = {0}; int r[] = {1}; int sx = 0; int sy = 0; int tx = 571; int ty = 571; string expected__ = "NO"; clock_t start__ = clock(); string received__ = CandyOnDisk().ableToAchieve(vector <int>(x, x + (sizeof x / sizeof x[0])), vector <int>(y, y + (sizeof y / sizeof y[0])), vector <int>(r, r + (sizeof r / sizeof r[0])), sx, sy, tx, ty); return verify_case(casenum, expected__, received__, clock()-start__); } case 3: { int x[] = {0}; int y[] = {0}; int r[] = {1}; int sx = 571; int sy = 571; int tx = 571; int ty = 571; string expected__ = "YES"; clock_t start__ = clock(); string received__ = CandyOnDisk().ableToAchieve(vector <int>(x, x + (sizeof x / sizeof x[0])), vector <int>(y, y + (sizeof y / sizeof y[0])), vector <int>(r, r + (sizeof r / sizeof r[0])), sx, sy, tx, ty); return verify_case(casenum, expected__, received__, clock()-start__); } case 4: { int x[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20}; int y[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20}; int r[] = {2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2}; int sx = 2; int sy = 2; int tx = 19; int ty = 19; string expected__ = "YES"; clock_t start__ = clock(); string received__ = CandyOnDisk().ableToAchieve(vector <int>(x, x + (sizeof x / sizeof x[0])), vector <int>(y, y + (sizeof y / sizeof y[0])), vector <int>(r, r + (sizeof r / sizeof r[0])), sx, sy, tx, ty); return verify_case(casenum, expected__, received__, clock()-start__); } case 5: { int x[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20}; int y[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20}; int r[] = {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}; int sx = 2; int sy = 2; int tx = 19; int ty = 19; string expected__ = "NO"; clock_t start__ = clock(); string received__ = CandyOnDisk().ableToAchieve(vector <int>(x, x + (sizeof x / sizeof x[0])), vector <int>(y, y + (sizeof y / sizeof y[0])), vector <int>(r, r + (sizeof r / sizeof r[0])), sx, sy, tx, ty); return verify_case(casenum, expected__, received__, clock()-start__); } // custom cases case 6: { int x[] = {69, 70, 78, 79, 88, 89, 92, 98, 98, 107, 108, 113, 118, 120, 125, 125, 133, 139, 142, 147, 157, 160, 167, 177, 185, 192, 193, 195, 202, 205, 211, 220, 225, 230, 236, 243, 243, 252, 256, 266, 268, 276, 284, 285, 289, 294, 297, 299, 299, 307}; int y[] = {-76, -69, -60, -53, -47, -40, -30, -27, -21, -20, -19, -15, -11, -8, -1, 5, 12, 13, 14, 24, 28, 31, 34, 41, 46, 48, 56, 66, 76, 84, 89, 92, 98, 103, 103, 108, 110, 117, 117, 126, 129, 136, 146, 149, 159, 164, 164, 173, 174, 174}; int r[] = {10, 10, 14, 4, 17, 15, 3, 18, 2, 16, 18, 5, 8, 13, 20, 4, 20, 12, 15, 9, 7, 16, 5, 14, 9, 19, 6, 7, 14, 10, 14, 5, 16, 13, 6, 20, 4, 7, 7, 6, 11, 9, 18, 12, 12, 19, 15, 17, 4, 10}; int sx = 65; int sy = -75; int tx = 286; int ty = 149; string expected__ = "YES"; clock_t start__ = clock(); string received__ = CandyOnDisk().ableToAchieve(vector <int>(x, x + (sizeof x / sizeof x[0])), vector <int>(y, y + (sizeof y / sizeof y[0])), vector <int>(r, r + (sizeof r / sizeof r[0])), sx, sy, tx, ty); return verify_case(casenum, expected__, received__, clock()-start__); } case 7: { int x[] = {3, 4, 5, 5, 14, 21, 30, 30, 36, 43, 43, 49, 52, 55, 56, 63, 68, 71, 78, 80, 90, 99, 104, 108, 110, 115, 123, 129, 129, 137, 140, 145, 151, 154, 157, 166, 169, 171, 175, 178, 178, 180, 186, 196, 204, 206, 216, 218, 219, 229}; int y[] = {99, 106, 110, 114, 121, 123, 130, 138, 143, 146, 151, 161, 170, 177, 187, 193, 203, 205, 210, 219, 226, 228, 235, 239, 249, 253, 256, 265, 269, 277, 282, 282, 282, 284, 285, 290, 295, 295, 303, 304, 309, 317, 327, 330, 331, 341, 343, 346, 346, 351}; int r[] = {8, 18, 11, 13, 8, 12, 7, 10, 3, 5, 5, 11, 3, 2, 9, 15, 3, 9, 20, 2, 6, 17, 7, 10, 15, 15, 7, 15, 18, 10, 9, 6, 11, 19, 11, 4, 15, 3, 18, 2, 2, 9, 19, 17, 15, 19, 14, 16, 20, 15}; int sx = 3; int sy = 102; int tx = 201; int ty = 332; string expected__ = "NO"; clock_t start__ = clock(); string received__ = CandyOnDisk().ableToAchieve(vector <int>(x, x + (sizeof x / sizeof x[0])), vector <int>(y, y + (sizeof y / sizeof y[0])), vector <int>(r, r + (sizeof r / sizeof r[0])), sx, sy, tx, ty); return verify_case(casenum, expected__, received__, clock()-start__); } case 8: { int x[] = {0, 0}; int y[] = {0, 0}; int r[] = {1, 2}; int sx = 0; int sy = -1; int tx = 0; int ty = -2; string expected__ = "NO"; clock_t start__ = clock(); string received__ = CandyOnDisk().ableToAchieve(vector <int>(x, x + (sizeof x / sizeof x[0])), vector <int>(y, y + (sizeof y / sizeof y[0])), vector <int>(r, r + (sizeof r / sizeof r[0])), sx, sy, tx, ty); return verify_case(casenum, expected__, received__, clock()-start__); } case 9: { int x[] = {0, 0}; int y[] = {0, 1}; int r[] = {1000000000, 1000000000}; int sx = 700000000; int sy = 700000000; int tx = 1; int ty = 2; string expected__ = "YES"; clock_t start__ = clock(); string received__ = CandyOnDisk().ableToAchieve(vector <int>(x, x + (sizeof x / sizeof x[0])), vector <int>(y, y + (sizeof y / sizeof y[0])), vector <int>(r, r + (sizeof r / sizeof r[0])), sx, sy, tx, ty); return verify_case(casenum, expected__, received__, clock()-start__); } case 10: { int x[] = {92, 102, 102, 112, 120, 121, 124, 134, 140, 144, 144, 148, 155, 160, 168, 178, 181, 189, 196, 202, 203, 208, 208, 213, 215, 221, 231, 237, 240, 249, 254, 255, 256, 266, 272, 272, 278, 279, 283, 288, 289, 299, 301, 301, 301, 306, 311, 316, 318, 328}; int y[] = {5, 6, 6, 7, 7, 14, 18, 21, 29, 35, 37, 40, 46, 52, 55, 65, 68, 74, 79, 85, 88, 93, 103, 106, 115, 122, 122, 126, 133, 136, 145, 145, 153, 153, 159, 164, 174, 183, 190, 199, 209, 212, 213, 223, 229, 229, 229, 230, 235, 239}; int r[] = {10, 6, 2, 3, 2, 16, 16, 7, 8, 17, 10, 11, 16, 16, 18, 20, 9, 5, 5, 7, 13, 20, 11, 8, 10, 13, 10, 6, 2, 16, 18, 7, 14, 15, 11, 15, 17, 20, 9, 10, 2, 5, 10, 18, 19, 9, 8, 16, 2, 5}; int sx = 88; int sy = 0; int tx = 310; int ty = 229; string expected__ = "YES"; clock_t start__ = clock(); string received__ = CandyOnDisk().ableToAchieve(vector <int>(x, x + (sizeof x / sizeof x[0])), vector <int>(y, y + (sizeof y / sizeof y[0])), vector <int>(r, r + (sizeof r / sizeof r[0])), sx, sy, tx, ty); return verify_case(casenum, expected__, received__, clock()-start__); } case 11: { int x[] = {0}; int y[] = {0}; int r[] = {1000000000}; int sx = 999999998; int sy = 0; int tx = 999999998; int ty = 1; string expected__ = "NO"; clock_t start__ = clock(); string received__ = CandyOnDisk().ableToAchieve(vector <int>(x, x + (sizeof x / sizeof x[0])), vector <int>(y, y + (sizeof y / sizeof y[0])), vector <int>(r, r + (sizeof r / sizeof r[0])), sx, sy, tx, ty); return verify_case(casenum, expected__, received__, clock()-start__); } /* case 8: { int x[] = ; int y[] = ; int r[] = ; int sx = ; int sy = ; int tx = ; int ty = ; string expected__ = ; clock_t start__ = clock(); string received__ = CandyOnDisk().ableToAchieve(vector <int>(x, x + (sizeof x / sizeof x[0])), vector <int>(y, y + (sizeof y / sizeof y[0])), vector <int>(r, r + (sizeof r / sizeof r[0])), sx, sy, tx, ty); return verify_case(casenum, expected__, received__, clock()-start__); }*/ default: return -1; } } } int main(int argc, char *argv[]) { if (argc == 1) { moj_harness::run_test(); } else { for (int i=1; i<argc; ++i) moj_harness::run_test(atoi(argv[i])); } } // END CUT HERE
有问题欢迎与我讨论。。