HDU 4720 Naive and Silly Muggles
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4720
Naive and Silly Muggles
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 272 Accepted Submission(s): 192
Naive and silly "muggles"(who have no talents in magic) should absolutely not get into the circle, nor even on its border, or they will be in danger.
Given the position of a muggle, is he safe, or in serious danger?
For each test case there are four lines. Three lines come each with two integers xi and yi (|xi, yi| <= 10), indicating the three wizards' positions. Then a single line with two numbers qx and qy (|qx, qy| <= 10), indicating the muggle's position.
先让我吐槽一下控制精度是多么恶心,调了好几次精度。
再让我吐槽一下杭电的数据是多么地弱,我错误的代码提交都AC了。
这里把错误的代码也贴出来,大家可以找找看是哪里错了,增长一下经验。
1 #include<stdio.h> 2 #include<iostream> 3 using namespace std; 4 #include<queue> 5 #include<math.h> 6 #include<algorithm> 7 #include<string.h> 8 #include<stdlib.h> 9 #include<vector> 10 #include<set> 11 #include<map> 12 13 #define repA(p,q,i) for( int (i)=(p); (i)!=(q); ++(i) ) 14 #define repAE(p,q,i) for( int (i)=(p); (i)<=(q); ++(i) ) 15 #define repD(p,q,i) for( int (i)=(p); (i)!=(q); --(i) ) 16 #define repDE(p,q,i) for( int (i)=(p); (i)>=(q); --(i) ) 17 #define mini 1e-7 18 #define y0 yy0 19 #define y1 yy1 20 21 double x1,y1,x2,y2,x3,y3; 22 double x0,y0,x,y,xt0,yt0; 23 double a,b,c; 24 25 void solve(); 26 bool inLine(); 27 void solve1(); 28 void solve2(); 29 double threeSides(); 30 31 int main() 32 { 33 int test; scanf("%d",&test); 34 repAE(1,test,round) 35 { 36 cin>>x1>>y1; 37 cin>>x2>>y2; 38 cin>>x3>>y3; 39 cin>>x>>y; 40 a = sqrt( (x1-x2)*(x1-x2) + (y1-y2)*(y1-y2) ) ; 41 b = sqrt( (x1-x3)*(x1-x3) + (y1-y3)*(y1-y3) ) ; 42 c = sqrt( (x3-x2)*(x3-x2) + (y3-y2)*(y3-y2) ) ; 43 printf("Case #%d: ",round); 44 solve(); 45 } 46 return 0; 47 } 48 49 void solve() 50 { 51 if( inLine() ) 52 solve1(); 53 else solve2(); 54 return ; 55 } 56 57 bool inLine() 58 { 59 60 if( fabs( (y1-y2)/(x1-x2) - (y1-y3)/(x1-x3) ) < mini \ 61 || (y1-y2)/(x1-x2) == (y1-y3)/(x1-x3) ) 62 return true ; //其它共线 63 return false ; 64 } 65 66 void solve1() 67 { 68 69 double A = y1 - y2 ; 70 double B = x2 - x1 ; 71 double C = x1*y2 - x2*y1 ; 72 double r ; 73 r = max(a,b); 74 r = max( r , c ); 75 r /= 2 ; 76 double dis = fabs(A*x + B*y + C)/sqrt(A*A+B*B) ; 77 if( r - dis >= mini || r == dis ) 78 printf("Danger\n"); 79 else printf("Safe\n"); 80 return ; 81 } 82 83 void solve2() 84 { 85 double r = threeSides() ; 86 double u1 = (x2*x2 - x1*x1 + y2*y2 - y1*y1) / 2 ; 87 double u2 = (x3*x3 - x1*x1 + y3*y3 - y1*y1) / 2 ; 88 double d11 = x2 - x1 ; 89 double d12 = y2 - y1 ; 90 double d21 = x3 - x1 ; 91 double d22 = y3 - y1 ; 92 x0 = (u1*d22 - u2*d12)/(d11*d22 - d21*d12) ; 93 y0 = (u2*d11 - u1*d21)/(d11*d22 - d21*d12) ; 94 if( r - sqrt( (x0-x1)*(x0-x1) + (y0-y1)*(y0-y1) ) <= mini ) 95 { 96 x0 = xt0 ; y0 = yt0 ; 97 } 98 else r = sqrt( (x0-x1)*(x0-x1) + (y0-y1)*(y0-y1) ) ; 99 //printf("x0 y0 r : %lf %lf %lf\n",x0,y0,r); 100 double dis = sqrt( (x0-x)*(x0-x) + (y0-y)*(y0-y) ) ; 101 if( r - dis > mini || r == dis ) 102 printf("Danger\n"); 103 else printf("Safe\n"); 104 return ; 105 } 106 107 double threeSides() 108 { 109 double xm,ym; 110 double rt1,rt2,r=0x3f3f3f3f; 111 rt1 = a/2 ; 112 xm = (x1+x2)/2 ; ym = (y1+y2)/2 ; 113 rt2 = sqrt( (xm-x3)*(xm-x3) + (ym-y3)*(ym-y3) ) ; 114 rt1 = max(rt1 , rt2) ; 115 if(rt1 - r < mini) 116 { r=rt1; xt0=xm; yt0=ym; } 117 118 rt1 = b/2 ; 119 xm = (x1+x3)/2 ; ym = (y1+y3)/2 ; 120 rt2 = sqrt( (xm-x2)*(xm-x2) + (ym-y2)*(ym-y2) ) ; 121 rt1 = max(rt1 , rt2) ; 122 if(rt1 - r < mini) 123 { r=rt1; xt0=xm; yt0=ym; } 124 125 rt1 = c/2 ; 126 xm = (x3+x2)/2 ; ym = (y3+y2)/2 ; 127 rt2 = sqrt( (xm-x1)*(xm-x1) + (ym-y1)*(ym-y1) ) ; 128 rt1 = max(rt1 , rt2) ; 129 if(rt1 - r < mini) 130 { r=rt1; xt0=xm; yt0=ym; } 131 132 return r ; 133 }
下面讲一下这道题的思路。
题意就是,给三个点,求一个圆,使三个点在圆内或者圆上,并且这个圆是所有圆中最小的那一个。
然后给出muggle的位置,如果muggle在圆内或圆上,输出Danger,否则输出Safe。
这个题目就转化为求这个最小圆的问题。
可能很多人都会觉得这就是三角形外接圆,no no no。
譬如对于一个钝角三角形,这种情况:
这时应取钝角对边上的中点为圆心,钝角对边边长的1/2为半径。
所以求解的时候要分两种情况来求解。
一、三点共线: 显然要取首尾端点所成线段的中点为圆心,线段长度的1/2作半径。
但其实判断三点是否共线的函数是很复杂的。
我的错误的代码中判断三点共线的函数是inLine()函数。
而大家去看这个代码的话会发现:
当三点水平共线或者三点竖直共线的话,我的函数都是没办法判断的。
但是这个代码居然水过去了。
二、三点不共线:
1、设三定点分别为A,B,C,三边中点分别为ma,mb,mc,三边长分别为a,b,c。
以边a为例,对三条边分别做一下操作
rt11 = a/2 ; rt12 = distanceBetween(ma,A) ; rt11 = max(rt11,rt12)
然后 r1 = min(rt11,rt21,rt31) ;
这里的r就是,如果圆心在三边中点之一的情况下,r1的最小值(因为题中有说要是最小圆)。
当然同时还要记录这个r所对应的圆心。我的代码中这一步由threeSides()函数来完成。
2、求解外接圆半径r2,及其圆心。
外接圆半径求法详见:http://www.cnblogs.com/overcode/p/3320657.html
最终 r = min(r1 , r2 ); 其对应的圆心设为x0,y0。
我的代码中这一步由solve2()函数来完成。
以上两步做完后,就可以以(x0,y0)为圆心,r为半径做圆,如果muggle在圆上或圆内就输出Danger,否则输出Safe。
同样要注意控制精度。
下面是正确的代码,几何题真的是体力活啊。
1 #include<stdio.h> 2 #include<iostream> 3 using namespace std; 4 #include<queue> 5 #include<math.h> 6 #include<algorithm> 7 #include<string.h> 8 #include<stdlib.h> 9 #include<vector> 10 #include<set> 11 #include<map> 12 13 #define repA(p,q,i) for( int (i)=(p); (i)!=(q); ++(i) ) 14 #define repAE(p,q,i) for( int (i)=(p); (i)<=(q); ++(i) ) 15 #define repD(p,q,i) for( int (i)=(p); (i)!=(q); --(i) ) 16 #define repDE(p,q,i) for( int (i)=(p); (i)>=(q); --(i) ) 17 #define mini 1e-7 18 #define y0 yy0 19 #define y1 yy1 20 21 double x1,y1,x2,y2,x3,y3; 22 double x0,y0,x,y,xt0,yt0; 23 double a,b,c; 24 25 void solve(); 26 bool inLine(); 27 void solve1(); 28 void solve2(); 29 double threeSides(); 30 31 int main() 32 { 33 int test; scanf("%d",&test); 34 repAE(1,test,round) 35 { 36 cin>>x1>>y1; 37 cin>>x2>>y2; 38 cin>>x3>>y3; 39 cin>>x>>y; 40 a = sqrt( (x1-x2)*(x1-x2) + (y1-y2)*(y1-y2) ) ; 41 b = sqrt( (x1-x3)*(x1-x3) + (y1-y3)*(y1-y3) ) ; 42 c = sqrt( (x3-x2)*(x3-x2) + (y3-y2)*(y3-y2) ) ; 43 printf("Case #%d: ",round); 44 solve(); 45 } 46 return 0; 47 } 48 49 void solve() 50 { 51 if( inLine() ) 52 solve1(); 53 else solve2(); 54 return ; 55 } 56 57 bool inLine() 58 { 59 if( (fabs(y1-y2) < mini) && (fabs(y1-y3) < mini) ) 60 return true; //水平共线 61 else if ( (fabs(x1-x2) < mini) && (fabs(x1-x3) < mini) ) 62 return true; //竖直共线 63 else if( fabs( (y1-y2)/(x1-x2) - (y1-y3)/(x1-x3) ) < mini \ 64 || (y1-y2)/(x1-x2) == (y1-y3)/(x1-x3) ) 65 return true ; //其它共线 66 return false ; 67 } 68 69 void solve1() 70 { 71 72 double A = y1 - y2 ; 73 double B = x2 - x1 ; 74 double C = x1*y2 - x2*y1 ; 75 double r ; 76 r = max(a,b); 77 r = max( r , c ); 78 r /= 2 ; 79 double dis = fabs(A*x + B*y + C)/sqrt(A*A+B*B) ; 80 if( r - dis >= mini || r == dis ) 81 printf("Danger\n"); 82 else printf("Safe\n"); 83 return ; 84 } 85 86 void solve2() 87 { 88 double r = threeSides() ; 89 double u1 = (x2*x2 - x1*x1 + y2*y2 - y1*y1) / 2 ; 90 double u2 = (x3*x3 - x1*x1 + y3*y3 - y1*y1) / 2 ; 91 double d11 = x2 - x1 ; 92 double d12 = y2 - y1 ; 93 double d21 = x3 - x1 ; 94 double d22 = y3 - y1 ; 95 x0 = (u1*d22 - u2*d12)/(d11*d22 - d21*d12) ; 96 y0 = (u2*d11 - u1*d21)/(d11*d22 - d21*d12) ; 97 if( r - sqrt( (x0-x1)*(x0-x1) + (y0-y1)*(y0-y1) ) <= mini ) 98 { 99 x0 = xt0 ; y0 = yt0 ; 100 } 101 else r = sqrt( (x0-x1)*(x0-x1) + (y0-y1)*(y0-y1) ) ; 102 //printf("x0 y0 r : %lf %lf %lf\n",x0,y0,r); 103 double dis = sqrt( (x0-x)*(x0-x) + (y0-y)*(y0-y) ) ; 104 if( r - dis > mini || r == dis ) 105 printf("Danger\n"); 106 else printf("Safe\n"); 107 return ; 108 } 109 110 double threeSides() 111 { 112 double xm,ym; 113 double rt1,rt2,r=0x3f3f3f3f; 114 rt1 = a/2 ; 115 xm = (x1+x2)/2 ; ym = (y1+y2)/2 ; 116 rt2 = sqrt( (xm-x3)*(xm-x3) + (ym-y3)*(ym-y3) ) ; 117 rt1 = max(rt1 , rt2) ; 118 if(rt1 - r < mini) 119 { r=rt1; xt0=xm; yt0=ym; } 120 121 rt1 = b/2 ; 122 xm = (x1+x3)/2 ; ym = (y1+y3)/2 ; 123 rt2 = sqrt( (xm-x2)*(xm-x2) + (ym-y2)*(ym-y2) ) ; 124 rt1 = max(rt1 , rt2) ; 125 if(rt1 - r < mini) 126 { r=rt1; xt0=xm; yt0=ym; } 127 128 rt1 = c/2 ; 129 xm = (x3+x2)/2 ; ym = (y3+y2)/2 ; 130 rt2 = sqrt( (xm-x1)*(xm-x1) + (ym-y1)*(ym-y1) ) ; 131 rt1 = max(rt1 , rt2) ; 132 if(rt1 - r < mini) 133 { r=rt1; xt0=xm; yt0=ym; } 134 135 return r ; 136 }