转载请注明出处,谢谢http://blog.csdn.net/dslovemz by---Dshawn
Problem Statement | |||||||||||||
Fox Ciel is playing the "DJ Box" set of levels in the "Cut the Rope" game on her smartphone.In the current level, she is facing the following problem: The level can be seen as a two-dimensional plane that contains a single candy and some disks.You are given the description of the level: vector <int>sx,y, andr; and intssx, sy, tx, andty. The vector <int>s x, y, and r describe the disks:For each i, there is a disk centered at (x[i],y[i]) with radiusr[i].Some of the disks may overlap.The candy is initially located at (sx,sy), and the goal of the game is to move it to (tx,ty). The game is played by rotating some of the disks, one after another.More precisely, in each step, Ciel may choose any disk that currently contains the candy, and rotate the disk by any desired angle around its center.The candy rotates with the chosen disk.Other disks are ignored during the rotation.(If the candy is located exactly on the border of a disk, we still consider it to be on the disk.) Return "YES" if she can solve the level in finitely many steps, and "NO" otherwise. | |||||||||||||
Definition | |||||||||||||
| |||||||||||||
Constraints | |||||||||||||
- | x will contain between 1 and 50 elements, inclusive. | ||||||||||||
- | x, y, and r will each contain the same number of elements. | ||||||||||||
- | Each element in x, y will be between -1,000,000,000 and 1,000,000,000, inclusive. | ||||||||||||
- | Each element in r will be between 1 and 1,000,000,000, inclusive. | ||||||||||||
- | sx, sy, tx and ty will be between -1,000,000,000 and 1,000,000,000, inclusive. | ||||||||||||
- | The answer will not change if we increase the radii of all disks by 1e-3. Neither will it change if we decrease the radii of all disks by 1e-3. | ||||||||||||
Examples | |||||||||||||
0) | |||||||||||||
| |||||||||||||
1) | |||||||||||||
| |||||||||||||
2) | |||||||||||||
| |||||||||||||
3) | |||||||||||||
| |||||||||||||
4) | |||||||||||||
| |||||||||||||
5) | |||||||||||||
|
题意:
给出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在某个可达圆环组上或者圆环组内那么就是可达的。
Attention
1、见Data 11 , 需要很明确距离用long double 来保存。。真是贱啊。。。
2、同心圆不可消除T_T
3、精度判断 dblcmp
4、圆之间的转换 dfs 内3部分:整理先前结果、查询当前所在区间、圆间转换
Code
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
Code 中包含了System Test 里面比较容易错的7组。
有问题欢迎与我讨论。。