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


Problem Description
Three wizards are doing a experiment. To avoid from bothering, a special magic is set around them. The magic forms a circle, which covers those three wizards, in other words, all of them are inside or on the border of the circle. And due to save the magic power, circle's area should as smaller as it could be.
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?
 

 

Input
The first line has a number T (T <= 10) , indicating the number of test cases.
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.
 

 

Output
For test case X, output "Case #X: " first, then output "Danger" or "Safe".
 

 

Sample Input
3 0 0 2 0 1 2 1 -0.5 0 0 2 0 1 2 1 -0.6 0 0 3 0 1 1 1 -1.5
 

 

Sample Output
Case #1: Danger Case #2: Safe Case #3: Safe
 

 

Source
 

 

Recommend
zhuyuanchen520
 
几何体,体力活。

先让我吐槽一下控制精度是多么恶心,调了好几次精度。

再让我吐槽一下杭电的数据是多么地弱,我错误的代码提交都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 }
正确的代码

 

posted on 2013-09-14 01:51  码农之上~  阅读(241)  评论(0编辑  收藏  举报

导航