计算几何

近来比较流行几何的碰撞问题。解析几何在其中就发挥着非常大的作用。解析几何一般模板较多,代码非常长,并有可能牵系到旋转,对称,求交点,反射等实复杂模拟。不仅需要个人思路清晰,步步为营,更需要对模板有着炉火纯青的掌握与使用。

Problem : 3834 ( Where am I )  :

这是前几天HDoj比赛中的一道解析几何题,当初刚接触几何,有点想法,但不知如何下手。昨天重拾此题,但由于对解析几何的模板不熟悉,花了大半天时间还没有做出这个题。今天晚饭前百度了下,看懂了(自己对模板,向量,极坐标的理解还不够深入)。睡前花了一个小时AC之。(粘贴+敲代码用了半个小时,一步步查找错误用了半个小时。)


图片

View Code

Problem : 3834 ( Where am I )     Judge Status : Accepted
RunId : 4247553    Language : C++    Author : ccsu2009021212
Code Render Status : Rendered By HDOJ C++ Code Render Version 0.01 Bet
#include <cmath > 
#include<iostream>
#include<stdio.h>
using namespace std;
/* 常用的常量定义 */ 
const double INF  = 1E200;    
const double EP  = 1E-10; 
const int  MAXV = 300; 
const double PI = acos(-1.0);
struct POINT 
{ 
 double x; 
 double y; 
 POINT(double a=0, double b=0) { x=a; y=b;} //constructor 
}; 
struct LINESEG 
{ 
 POINT s; 
 POINT e; 
 LINESEG(POINT a, POINT b) { s=a; e=b;} 
 LINESEG() { } 
}; 
struct LINE           // 直线的解析方程 a*x+b*y+c=0  为统一表示,约定 a >= 0 
{ 
   double a; 
   double b; 
   double c; 
   LINE(double d1=1, double d2=-1, double d3=0) {a=d1; b=d2; c=d3;} 
}; 
LINE getline(POINT p1,POINT p2) 
{ 
 LINE tl; 
 int sign = 1; 
 tl.a=p2.y-p1.y; 
 if(tl.a<0) 
 { 
  sign = -1; 
  tl.a=sign*tl.a; 
 } 
 tl.b=sign*(p1.x-p2.x); 
 tl.c=sign*(p1.y*p2.x-p1.x*p2.y); 
 return tl; 
} 

double dist(POINT p1,POINT p2)                
{ 
 return( sqrt( (p1.x-p2.x)*(p1.x-p2.x)+(p1.y-p2.y)*(p1.y-p2.y) ) ); 
} 
bool equal_point(POINT p1,POINT p2)           // 判断两个点是否重合  
{ 
 return ( (abs(p1.x-p2.x)<EP)&&(abs(p1.y-p2.y)<EP) ); 
}

int clpoint(POINT p,double r,double a,double b,double c,POINT &rp1,POINT &rp2) 
{ 
 int res=0; 
 c=c+a*p.x+b*p.y; 
 double tmp; 
 if(a==0&&b!=0) 
 { 
  tmp=-c/b; 
  if(r*r<tmp*tmp) 
   res=0; 
  else if(r*r==tmp*tmp) 
  { 
   res=1; 
   rp1.y=tmp; 
   rp1.x=0; 
  } 
  else 
  { 
   res=2; 
   rp1.y=rp2.y=tmp; 
   rp1.x=sqrt(r*r-tmp*tmp); 
   rp2.x=-rp1.x; 
  } 
 } 
 else if(a!=0&&b==0) 
 { 
  tmp=-c/a; 
  if(r*r<tmp*tmp) 
   res=0; 
  else if(r*r==tmp*tmp) 
  { 
   res=1; 
   rp1.x=tmp; 
   rp1.y=0; 
  } 
  else 
  { 
   res=2; 
   rp1.x=rp2.x=tmp; 
   rp1.y=sqrt(r*r-tmp*tmp); 
   rp2.y=-rp1.y; 
  } 
 } 
 else if(a!=0&&b!=0) 
 { 
  double delta; 
  delta=b*b*c*c-(a*a+b*b)*(c*c-a*a*r*r); 
  if(delta<0) 
   res=0; 
  else if(delta==0) 
  { 
   res=1; 
   rp1.y=-b*c/(a*a+b*b); 
   rp1.x=(-c-b*rp1.y)/a; 
  } 
  else 
  { 
   res=2; 
   rp1.y=(-b*c+sqrt(delta))/(a*a+b*b); 
   rp2.y=(-b*c-sqrt(delta))/(a*a+b*b); 
   rp1.x=(-c-b*rp1.y)/a; 
   rp2.x=(-c-b*rp2.y)/a; 
  } 
 } 
 rp1.x+=p.x; 
 rp1.y+=p.y; 
 rp2.x+=p.x; 
 rp2.y+=p.y; 
 return res; 
}
double angle(POINT o,POINT s,POINT e) 
{ 
 double cosfi,fi,norm; 
 double dsx = s.x - o.x; 
 double dsy = s.y - o.y; 
 double dex = e.x - o.x; 
 double dey = e.y - o.y; 

 cosfi=dsx*dex+dsy*dey; 
 norm=(dsx*dsx+dsy*dsy)*(dex*dex+dey*dey); 
 cosfi /= sqrt( norm ); 

 if (cosfi >=  1.0 ) return 0; 
 if (cosfi <= -1.0 ) return -3.1415926; 

 fi=acos(cosfi); 
 if (dsx*dey-dsy*dex>0) return fi;      // 说明矢量os 在矢量 oe的顺时针方向 
 return -fi; 
} 
POINT rotate(POINT v,POINT o,double angle,double scale)//
{
        POINT ret=o;
        v.x-=o.x,v.y-=o.y;
        o.x=scale*cos(angle);
        o.y=scale*sin(angle);
        ret.x+=v.x*o.x-v.y*o.y;
        ret.y+=v.x*o.y+v.y*o.x;
        return ret;
}
int main()
{
    int tt;
    scanf("%d",&tt);
    while(tt--)
    {
               POINT o,s,e;
               double r,r1,dx,dy,t;
               scanf("%lf%lf%lf",&o.x,&o.y,&r);
               scanf("%lf%lf%lf",&s.x,&s.y,&r1);
               scanf("%lf%lf%lf",&dx,&dy,&t);
               r-=r1;
               e.x=s.x+dx;e.y=s.y+dy; 
               LINE l1=getline(s,e);
               POINT x,y,cur;
               clpoint(o,r,l1.a,l1.b,l1.c,x,y);
               if((dx>0 && x.x>y.x)||(dx<0 && x.x<y.x)||(dy>0 && x.y>y.y)||(dy<0 && x.y<y.y));
               else{cur=x,x=y,y=cur;}
               double left=dist(x,s);
               if(left>=sqrt(dx*dx+dy*dy)*t)
               {
                          printf("%.1lf %lf.1\n",s.x+t*dx,s.y+t*dy);
                          continue;
               }
               t=sqrt(dx*dx+dy*dy)*t;
               t-=left;
               double rad=angle(o,x,y);
               double len=fabs(r*sin(rad/2)*2);
               double turn=floor(t/len);
               left=t-turn*len;
               POINT now1,now2;
               rad*=-1;
               now1=rotate(x,o,rad*turn,1.0);
               now2=rotate(x,o,rad*(turn+1),1.0);
               POINT ret;
               ret.x=now1.x+(now2.x-now1.x)*left/len;
               ret.y=now1.y+(now2.y-now1.y)*left/len;
               printf("%.1lf %.1lf\n",ret.x,ret.y);
    }
}
图片
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值