AOJ 2537 Billiard

来源:互联网 发布:sql备份与恢复 编辑:程序博客网 时间:2024/05/18 03:27


Aizu 2537

题意:打台球,已知母球及所有球的半径、位置,求母球打出后第一个碰到的球的编号。


计算几何的模拟。

考虑每个球的中心点,母球中心的运动轨迹只在台的中央,由(r, r), (r, w-r), (h-r, w-r), (h-r, r)四个点组成的矩形内部。

将其设为新的四边,沿着运动方向的射线去和这些边求交点,经过反射后的每个球的坐标可以预处理出来。

模拟至运动距离上限10000即可。



#include <bits/stdc++.h>using namespace std;typedef complex<double> point;typedef point Vec;const int MAXN=15;const double eps=1.0e-9;point cueball, current, previous, nextpos, midpoint, ball[MAXN][2][2];point board[4];struct line : public vector<point> {    line() {}    line(const point& a, const point& b) { push_back(a); push_back(b); }};struct Circle{    point center;    double radius;    Circle(const point& c, const double& r):center(c),radius(r) {}};point unit(const point& v) { return v/abs(v);}inline double dot  (const point& a, const point& b) { return (a*conj(b)).real();}inline double cross(const point& a, const point& b) { return (conj(a)*b).imag();}inline point vec(const line& l) { return l[1]-l[0];}bool intersectSP(const line& s, const point& p) {    return abs(s[0]-p)+abs(s[1]-p) < abs(s[1]-s[0])+eps;}point crosspoint(const line& l, const line& m) {    ///use Intersection Judging first    double A = cross(vec(l), vec(m));    double B = cross(vec(l), l[1]-m[0]);    if(abs(A)<eps) {    // parallel        return m[0];    // sameline    }    return m[0] + B/A*vec(m);}point intersection_point(const line& A, const Circle& C){    double dx=real(A[1]-A[0]), dy=imag(A[1]-A[0]);    double rx=real(A[0]-C.center), ry=imag(A[0]-C.center);    double a=dx*dx+dy*dy, b=2*dx*rx+2*dy*ry, c=rx*rx+ry*ry-C.radius*C.radius;    double delta=b*b-4*a*c;    if(delta<-eps) return point(-100000,-100000);    delta=max(0.0,delta);    double ans=(-b-sqrt(delta))/(2.0*a);    if(ans>=0) return point(A[0].real()+ans*dx,A[0].imag()+ans*dy);    ans=(-b+sqrt(delta))/(2.0*a);    if(ans>=0) return point(A[0].real()+ans*dx,A[0].imag()+ans*dy);    return point(-100000,-100000);}int main(){    int n, w, h, r, v_x, v_y;    Vec direction;    while(cin>>n&&n){        cin>>w>>h>>r>>v_x>>v_y;        w-=r*2, h-=r*2;        direction=point(v_x,v_y);        direction=unit(direction);        for(int i=0, x, y; i<n; i++){            scanf("%d%d",&x,&y);            x-=r; y-=r;            if(i==0) cueball=point(x,y);            else ball[i-1][0][0]=point(x,y);        }        n--;        point tmp;        for(int i=0; i<n; i++){            tmp=ball[i][0][0];            double x=tmp.real(), y=tmp.imag();            ball[i][0][1]=point(x,h-y);            ball[i][1][0]=point(w-x,y);            ball[i][1][1]=point(w-x,h-y);        }        double dist=0;        int ans=-1;        int nowx=0, nowy=0, nextx=0, nexty=0;        current=cueball;        while(dist<=10000){            previous=current;            nowx=nextx; nowy=nexty;            board[0]=point(nowx*w,nowy*h);            board[1]=point((nowx+1)*w,nowy*h);            board[2]=point((nowx+1)*w,(nowy+1)*h);            board[3]=point(nowx*w,(nowy+1)*h);            double ret=0;            for(int i=0; i<4; i++){                tmp=crosspoint(line(board[i], board[(i+1)%4]), line(previous, previous+direction));                if(intersectSP(line(board[i], board[(i+1)%4]), tmp) && dot(previous-tmp, previous+100000.0*direction-tmp)<0 && abs(tmp-previous)>ret){                    ret=abs(tmp-previous);                    current=tmp;                }            }            midpoint=current+direction;            nextx=floor(midpoint.real()/w);            nexty=floor(midpoint.imag()/h);            double ansdist=1.0e20;            for(int i=0; i<n; i++){                tmp=ball[i][nowx&1][nowy&1]+point(nowx*w,nowy*h);                point intersect=intersection_point(line(previous,current),Circle(tmp,2*r));                if(intersect!=point(-100000,-100000)){                    double ndist=abs(intersect-previous);                    if(ndist<ansdist&&dist+ndist<=10000){                        ansdist=ndist;                        ans=i+2;                    }                }            }            if(ans!=-1){                break;            }            dist+=ret;        }        printf("%d\n",ans);    }    return 0;}


0 0
原创粉丝点击