计蒜客 16951 Out-out-control cars(计算几何)

Description

给出两个三角形的三个顶点坐标和其速度向量,问两个三角形是否可能相交

Input

第一行一整数 T T 表示用例组数,每组用例输入两行,一行八个整数分别表示三角形三点坐标和速度向量,绝对值均不超过109

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 点出发, 以v为速度向量的射线相交,如果 ab a b v v 平行,c点只有在直线 ab a b 上才可能与线段 ab a b 相交,此时根据 ax=cx+tvx a x = c x + t ⋅ v x 解出 t t 如果非负说明c可以运动到 a a ,同理bx=cx+tvx解出 t t 如果非负说明c可以运动到 b b ,如果这两种情况都不行说明不相交;如果ab v v 不平行,那么直线ab与过 c c 点以v为方向的直线必然相交,此时如果要与线段 ab a b 相交,那么 v v 向量应该在ac bc b − c 这两个向量之间,且 c c 点以速度v运动非负时间应该出现在直线 ab a b 上,即 c+tv c + t ⋅ v 应该出现在 ycy=byaybxax(xcx) y − c y = b y − a y b x − a x ⋅ ( x − c x ) ,即 t=(ca)×(ba)(ba)×v0 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;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值