Description
给出两个三角形的三个顶点坐标和其速度向量,问两个三角形是否可能相交
Input
第一行一整数 T T 表示用例组数,每组用例输入两行,一行八个整数分别表示三角形三点坐标和速度向量,绝对值均不超过
Output
如果两个三角形可以相交则输出 YES Y E S ,否则输出 NO N O
Sample Input
3
0 1 2 1 1 3 1 0
9 2 10 4 8 4 -1 0
0 1 2 1 1 3 2 0
9 2 10 4 8 4 3 0
0 1 2 1 1 3 0 0
0 4 1 6 -1 6 1 -2
Sample Output
Case #1: YES
Case #2: NO
Case #3: YES
Solution
先固定一个三角形,那么问题变成判断一个三角形以相对速度运动是否与固定的三角形相交,由于两个三角形相交必然是某个三角形某个顶点自开始运动所形成的射线和另一个三角形的某条边相交,故枚举固定的三角形,枚举动的三角形的顶点,枚举固定的三角形的一条边,判断射线与线段是否相交即可
判断线段 ab a b 是否和从 c c 点出发, 以为速度向量的射线相交,如果 ab a b 与 v v 平行,点只有在直线 ab a b 上才可能与线段 ab a b 相交,此时根据 ax=cx+t⋅vx a x = c x + t ⋅ v x 解出 t t 如果非负说明可以运动到 a a ,同理解出 t t 如果非负说明可以运动到 b b ,如果这两种情况都不行说明不相交;如果与 v v 不平行,那么直线与过 c c 点以为方向的直线必然相交,此时如果要与线段 ab a b 相交,那么 v v 向量应该在和 b−c b − c 这两个向量之间,且 c c 点以速度运动非负时间应该出现在直线 ab a b 上,即 c+t⋅v c + t ⋅ v 应该出现在 y−cy=by−aybx−ax⋅(x−cx) y − c y = b y − a y b x − a x ⋅ ( x − c x ) ,即 t=(c−a)×(b−a)(b−a)×v≥0 t = ( c − a ) × ( b − a ) ( b − a ) × v ≥ 0 ,只要保证分子分母这两个叉积符号乘积非负即可
Code
#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<vector>
#include<queue>
#include<map>
#include<set>
#include<ctime>
using namespace std;
typedef long long ll;
typedef pair<int,int>P;
const int INF=0x3f3f3f3f,maxn=100001;
struct Point
{
int x,y;
Point(){}
Point(int _x,int _y)
{
x=_x;y=_y;
}
Point operator -(const Point &b)const
{
return Point(x-b.x,y-b.y);
}
};
int mul(Point a,Point b)
{
ll ans=(ll)a.x*b.y-(ll)a.y*b.x;
if(ans>0)return 1;
if(ans<0)return -1;
return 0;
}
int check(Point a,Point b,Point c,Point v)
{
if(mul(b-a,v)==0)
{
if(mul(a-c,b-c))return 0;
if((ll)v.x*(a.x-c.x)>=0||(ll)v.x*(b.x-c.x)>=0)return 1;
return 0;
}
if(mul(c-a,b-a)*mul(b-a,v)>=0&&mul(a-c,v)*mul(b-c,v)<=0)return 1;
return 0;
}
int main()
{
Point a[3],b[3],v1,v2;
int T,Case=1;
scanf("%d",&T);
while(T--)
{
for(int i=0;i<3;i++)scanf("%d%d",&a[i].x,&a[i].y);
scanf("%d%d",&v1.x,&v1.y);
for(int i=0;i<3;i++)scanf("%d%d",&b[i].x,&b[i].y);
scanf("%d%d",&v2.x,&v2.y);
int flag=0;
for(int i=0;i<3;i++)
for(int j=0;j<3;j++)
for(int k=j+1;k<3;k++)
if(check(b[j],b[k],a[i],v1-v2))flag=1;
for(int i=0;i<3;i++)
for(int j=0;j<3;j++)
for(int k=j+1;k<3;k++)
if(check(a[j],a[k],b[i],v2-v1))flag=1;
printf("Case #%d: %s\n",Case++,flag?"YES":"NO");
}
return 0;
}