题目:给你两辆车的左后方和左前方的坐标,车宽和速度,将车看成矩形并分成四部分,问两辆车相撞的位置编号。
分析:计算几何、线与线的关系判断。
首先,先将分别运动的两车转移到相对参考系,利用速度向量做差即可。
然后,判断两车相撞,可以分成三种情况:点对点,点对线,线对线。由于点撞到点,一定撞到线上。
线对线可以转化成点对线,所以将所有情况转换成点对线即可。将四个顶点和各边的中点构成集合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;
}