Description
给出两个三角形的三个顶点坐标和其速度向量,问两个三角形是否可能相交
Input
第一行一整数TT表示用例组数,每组用例输入两行,一行八个整数分别表示三角形三点坐标和速度向量,绝对值均不超过
Output
如果两个三角形可以相交则输出YESYES,否则输出NONO
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
先固定一个三角形,那么问题变成判断一个三角形以相对速度运动是否与固定的三角形相交,由于两个三角形相交必然是某个三角形某个顶点自开始运动所形成的射线和另一个三角形的某条边相交,故枚举固定的三角形,枚举动的三角形的顶点,枚举固定的三角形的一条边,判断射线与线段是否相交即可
判断线段abab是否和从cc点出发, 以为速度向量的射线相交,如果abab与vv平行,点只有在直线abab上才可能与线段abab相交,此时根据ax=cx+t⋅vxax=cx+t⋅vx解出tt如果非负说明可以运动到aa,同理解出tt如果非负说明可以运动到bb,如果这两种情况都不行说明不相交;如果与vv不平行,那么直线与过cc点以为方向的直线必然相交,此时如果要与线段abab相交,那么vv向量应该在和b−cb−c这两个向量之间,且cc点以速度运动非负时间应该出现在直线abab上,即c+t⋅vc+t⋅v应该出现在y−cy=by−aybx−ax⋅(x−cx)y−cy=by−aybx−ax⋅(x−cx),即t=(c−a)×(b−a)(b−a)×v≥0t=(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;
}