题目:给你两辆车的左后方和左前方的坐标,车宽和速度,将车看成矩形并分成四部分,问两辆车相撞的位置编号。
分析:计算几何、线与线的关系判断。
首先,先将分别运动的两车转移到相对参考系,利用速度向量做差即可。
然后,判断两车相撞,可以分成三种情况:点对点,点对线,线对线。由于点撞到点,一定撞到线上。
线对线可以转化成点对线,所以将所有情况转换成点对线即可。将四个顶点和各边的中点构成集合A。
将四个顶点和相邻中点的连线构成的8条线段构成集合B。利用A集合的点做速度v方向的射线。
如果相撞,则射线一定与线段相交。计算A中的点与交点的距离,取最小的即为最先相撞的部分。
最后,让两辆车分别向对方相撞(速度相反),整理结果即可。
注意:1.精度问题;2.相撞的区域不一定是最优解,如下图,结果应该是1 1。
#include <iostream> #include <cstdlib> #include <cstdio> #include <cmath> #define esp 1e-6 using namespace std; //点结构 typedef struct pnode { double x,y; int id; pnode( double a, double b ){x = a;y = b;} pnode( double a, double b, int i ){x = a;y = b;id = i;} pnode(){} }point; //直线线结构 typedef struct lnode { double x,y,dx,dy; lnode( point a, point b ){x = a.x;y = a.y;dx = b.x-a.x;dy = b.y-a.y;} lnode(){} }line; //线段结构 typedef struct snode { point p1,p2; int id; snode( point a, point b, int i ){p1 = a;p2 = b;id = i;} snode(){} }segment; //车结构 typedef struct cnode { point p[8]; segment s[8]; }car; //构造结点和线段 car madecar( double x, double y, double u, double v, double w ) { car Car; Car.p[0] = point( x, y, 1 ); Car.p[2] = point( u, v, 2 ); double d = sqrt((x-u)*(x-u)+(y-v)*(y-v)); point r = point( (v-y)*w/d, (x-u)*w/d ); Car.p[4] = point( u+r.x, v+r.y, 3 ); Car.p[6] = point( x+r.x, y+r.y, 4 ); for ( int i = 0 ; i < 8 ; i += 2 ) { point m; m.x = (Car.p[i].x+Car.p[(i+2)%8].x)/2; m.y = (Car.p[i].y+Car.p[(i+2)%8].y)/2; m.id = min(Car.p[i].id,Car.p[(i+2)%8].id); Car.p[i+1] = m; } for ( int i = 0 ; i < 8 ; ++ i ) { Car.s[i] = segment( Car.p[i], Car.p[(i+1)%8], 0 ); Car.s[i].id = (i+1)%8/2+1; } return Car; } //两点间距离 double dist( point a, point b ) { return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y)); } //直线相交判断 bool lcrossl( line a, line b ) { double t1 = b.dx*(a.y-b.y)-b.dy*(a.x-b.x); double t2 = b.dx*(a.y+a.dy-b.y)-b.dy*(a.x+a.dx-b.x); return (t1-esp)*(t2-esp) <= 0; } //求直线交点 point crosspoint( line l, line m ) { point a = point( m.x, m.y ); point b = point( m.x+m.dx, m.y+m.dy ); if ( m.dx*l.dy == m.dy*l.dx ) { if ( dist( point( l.x, l.y ), a ) < dist( point( l.x, l.y ), b ) ) return a; else return b; }else { double a1 = -l.dy,b1 = l.dx,c1 = l.dx*l.y-l.dy*l.x; double a2 = -m.dy,b2 = m.dx,c2 = m.dx*m.y-m.dy*m.x; double x = (c1*b2-c2*b1)/(a1*b2-a2*b1); double y = (c1*a2-c2*a1)/(b1*a2-b2*a1); return point( x, y ); } } //结果结构 typedef struct anode { int id1,id2; double dis; anode( int a, int b, double d ){id1 = a;id2 = b;dis = d;} }answer; //判断a撞向b answer crash( car a, car b, point v ) { double dis = 1e20; int id1 = 1,id2 = 1; for ( int i = 0 ; i < 8 ; ++ i ) for ( int j = 0 ; j < 8 ; ++ j ) { point c = point( a.p[i].x+v.x, a.p[i].y+v.y ); line l = line( b.s[j].p1, b.s[j].p2 ); if ( lcrossl( l, line( a.p[i], c ) ) ) { point e = crosspoint( line( a.p[i], c ), l ); double d = dist( a.p[i], e ); if ( fabs(dis-d) < esp ) { if ( id1 > a.p[i].id ) id1 = a.p[i].id; if ( id2 > b.s[j].id ) id2 = b.s[j].id; } if ( dis-esp > d ) { dis = d; id1 = a.p[i].id; id2 = b.s[j].id; } } } return answer( id1, id2, dis ); } int main() { double x1,y1,u1,v1,w1,s1,x2,y2,u2,v2,w2,s2; while ( ~scanf("%lf%lf%lf%lf%lf%lf",&x1,&y1,&u1,&v1,&w1,&s1) ) { scanf("%lf%lf%lf%lf%lf%lf",&x2,&y2,&u2,&v2,&w2,&s2); //将输入转化成几何模型(8个点+8条线段) car A = madecar( x1, y1, u1, v1, w1 ); car B = madecar( x2, y2, u2, v2, w2 ); //计算速度向量 double d1 = sqrt((x1-u1)*(x1-u1)+(y1-v1)*(y1-v1)); point V1 = point( (u1-x1)*s1/d1, (v1-y1)*s1/d1 ); double d2 = sqrt((x2-u2)*(x2-u2)+(y2-v2)*(y2-v2)); point V2 = point( (u2-x2)*s2/d2, (v2-y2)*s2/d2 ); answer an1 = crash( A, B, point( V1.x-V2.x, V1.y-V2.y ) ); answer an2 = crash( B, A, point( V2.x-V1.x, V2.y-V1.y ) ); if ( fabs(an1.dis-an2.dis) < esp ) printf("%d %d\n",min(an1.id1,an2.id2),min(an1.id2,an2.id1)); else if ( an1.dis+esp < an2.dis ) printf("%d %d\n",an1.id1,an1.id2); else printf("%d %d\n",an2.id2,an2.id1); } return 0; }