第八届福建省大学生程序设计竞赛 FZU 2273 Triangles (计算几何)

题目原文:http://acm.fzu.edu.cn/problem.php?pid=2273

Problem B Triangles

Accept: 158    Submit: 754
Time Limit: 1000 mSec    Memory Limit : 262144 KB

 Problem Description

This is a simple problem. Given two triangles A and B, you should determine they are intersect, contain or disjoint. (Public edge or point are treated as intersect.)

 Input

First line contains an integer T (1 ≤ T ≤ 10), represents there are T test cases.

For each test case: X1 Y1 X2 Y2 X3 Y3 X4 Y4 X5 Y5 X6 Y6. All the coordinate are integer. (X1,Y1) , (X2,Y2), (X3,Y3) forms triangles A ; (X4,Y4) , (X5,Y5), (X6,Y6) forms triangles B.

-10000<=All the coordinate <=10000

 Output

For each test case, output “intersect”, “contain” or “disjoint”.

 Sample Input

20 0 0 1 1 0 10 10 9 9 9 100 0 1 1 1 0 0 0 1 1 0 1

 Sample Output

disjoint intersect


题目大意:给定两个三角形六个顶点,判断两个三角形的关系(相交、相离、包含)

解题思路:

(1)通过叉积判断点与线的关系,点与这条边对应的那个顶点位于这条边的同一侧,说明这个点在这条边的内测。如果一个点位于三条边的内侧,则这个点在三角形内。如果三个顶点都在这个三角形内,说明两个三角形是包含关系。

(2)通过判断线段相交的关系,可以确定两个三角形是否存在边相交

(3)其余情况说明两个三角形相离。

AC代码:

/*
    @Author: wchhlbt
    @Date:   2017/7/17
*/
#include <vector>
#include <list>
#include <map>
#include <set>
#include <queue>
#include <stack>
#include <bitset>
#include <algorithm>
#include <functional>
#include <numeric>
#include <utility>
#include <sstream>
#include <iostream>
#include <iomanip>
#include <cstdio>
#include <cmath>
#include <cstdlib>
#include <ctime>
#include <cstring>
#include <limits>
#include <climits>
#include <cstdio>

#define Fori(x) for(int i=0;i<x;i++)
#define Forj(x) for(int j=0;j<x;j++)
#define maxn 10007
#define inf 0x3f3f3f3f
#define ONES(x) __builtin_popcount(x)
#define _  << "  " <<
using namespace std;

typedef long long ll ;
const double eps =1e-8;
const int mod = 1000000007;
typedef pair<int, int> P;
const double PI = acos(-1.0);
int dx[4] = {0,0,1,-1};
int dy[4] = {1,-1,0,0};

typedef struct  Point
{
    double x,y;
    Point(double x=0,double y=0):x(x),y(y){}
}Vector;

Vector operator + (const Vector & A,const Vector & B) { return Vector(A.x+B.x,A.y+B.y);}
Vector operator - (const Point & A,const Point & B) { return Vector(A.x-B.x,A.y-B.y);}
Vector operator * (const Vector & A,double p) { return Vector(A.x*p,A.y*p);}
Vector operator / (const Vector & A,double p) { return Vector(A.x/p,A.y/p);}

bool operator < (const Point &A, const Point &B)
{
    return A.x<B.x||(A.x==B.x&&A.y<B.y);
}

int dcmp(double x)
{
    if(fabs(x)<eps) return 0;
    return  x<0? -1 : 1 ;
}

bool operator == (const Point &A,const Point &B)
{
    return dcmp(A.x-B.x)==0&&dcmp(A.y-B.y)==0;
}

//向量点乘
double Dot(const Vector &A, const Vector &B) {  return A.x*B.x+A.y*B.y;  }

//求向量的长度或两点距离
double Length(const Vector &A){ return sqrt(Dot(A,A)); }

//返回两个向量夹角的弧度值
double Angle(const Vector &A, const Vector &B)
{
    return  acos(Dot(A,B)/Length(A)/Length(B));
}

//向量叉积。共起点的两个向量A,B,若A叉乘B大于0,则B在A的左边。
double Cross(const Vector &A, const Vector &B){ return A.x*B.y-A.y*B.x ;}

//用叉积求三个点组成的三角形的面积。面积为0表示三点共线。
double Area2(const Point &A,const Point &B,const Point &C ){return Cross(B-A,C-A) ;}

//向量绕起点旋转,rad为逆时针旋转的弧度。
//Rotate(A,-rad)表示将A顺时针旋转rad
Vector Rotate(const Vector &A,double rad)
{
    return Vector(A.x*cos(rad)-A.y*sin(rad),A.x*sin(rad)+A.y*cos(rad));
}

//计算A向量的单位法向量,即左转90度,将单位归一化
//调用前确保A向量不是零向量
Vector Normal(Vector A)
{
    double L=Length(A);
    return Vector(-A.y/L,A.x/L);
}

//用直线的参数方程(P=P0+t*v,P0是直线上任意一点,v是直线的方向向量)求两直线的交点坐标
Point GetLineIntersection(const Point & P,const Vector & v,const Point & Q,const Vector & w)
{
    Vector u=P-Q;
    double t=Cross(w,u)/Cross(v,w);
    return P+v*t;
}

//点到直线的距离。平行四边形面积除以底
double DistanceToLine(const Point & P,const Point & A,const Point & B)
{
    Vector v1=B-A,v2=P-A;
    return fabs(Cross(v1,v2))/Length(v1);
}

//点到线段的距离
double DistanceToSegment(const Point & P,const Point & A,const Point & B)
{
    if(A==B)  return Length(P-A);
    Vector v1=B-A,v2=P-A,v3=P-B;
    if(dcmp(Dot(v1,v2))<0) return Length(v2);
    else if(dcmp(Dot(v1,v3))>0) return Length(v3);
    else return fabs(Cross(v1,v2))/Length(v1);
}

//点在直线上的投影
Point GetLineProjection(const Point & P,const Point & A,const Point & B)
{
    Vector v=B-A;
    return A+v*(Dot(v,P-A)/Dot(v,v));
}

//判断点P是否在线段AB(不含端点)上
bool OnSegment(const Point & P,const Point & A,const Point & B)
{
    return dcmp(Cross(A-P,B-P))==0 && dcmp(Dot(A-P,B-P)) <0 ;
}


//判断两线段是否规范相交(两条线段恰有一个公共点且不在任何一个线段的端点)
bool SegmentProperIntersection(const Point & a1,const Point & a2,const Point & b1,const Point & b2)
{
    double c1=Cross(a2-a1,b1-a1) ,c2=Cross(a2-a1,b2-a1);
    double c3=Cross(b2-b1,a1-b1) ,c4=Cross(b2-b1,a2-b1);
    return dcmp(c1)*dcmp(c2)<0 && dcmp(c3)*dcmp(c4)<0 ;
}

//判断两线段是否规范相交(两条线段可以部分重合或者相交在某一个线段的端点)
bool SegmentIntersection(const Point & a1,const Point & a2,const Point & b1,const Point & b2)
{
    double c1=Cross(a2-a1,b1-a1) ,c2=Cross(a2-a1,b2-a1);
    double c3=Cross(b2-b1,a1-b1) ,c4=Cross(b2-b1,a2-b1);
    return dcmp(c1)*dcmp(c2)<=0 && dcmp(c3)*dcmp(c4)<=0 ;
}

bool SameSide(Point A, Point B, Point C, Point D)//C和D是否在AB同一侧
{
    Vector AB = B-A;
    Vector AC = C-A;
    Vector AD = D-A;
    double aaa = Cross(AB,AC);
    double bbb = Cross(AB,AD);
    if(aaa*bbb>=0)  return true;

    // v1 and v2 should point to the same direction
    return false;
}

// Same side method
// Determine whether point D in triangle ABC
bool PointinTriangle1(Point A, Point B, Point C, Point D)
{
    return SameSide(A, B, C, D) &&
        SameSide(B, C, A, D) &&
        SameSide(C, A, B, D) ;
}

int main()
{
    int t;
    cin>>t;
    while(t--){
        int flag = 0;
        Point p[6];
        for(int i = 0; i<6; i++)
            cin>>p[i].x>>p[i].y;
        for(int i = 0; i<3; i++){
            if(SegmentIntersection(p[i],p[(i+1)%3],p[3],p[4]) || SegmentIntersection(p[i],p[(i+1)%3],p[3],p[5]) || SegmentIntersection(p[i],p[(i+1)%3],p[5],p[4]))
            {
                flag = 1;
                break;
            }
        }
        if(flag==1){
            cout << "intersect" << endl;
            continue;
        }
        if(PointinTriangle1(p[0],p[1],p[2],p[3]) && PointinTriangle1(p[0],p[1],p[2],p[4]) && PointinTriangle1(p[0],p[1],p[2],p[5])){
            cout << "contain" << endl;
            continue;
        }
        if(PointinTriangle1(p[3],p[4],p[5],p[0]) && PointinTriangle1(p[3],p[4],p[5],p[1]) && PointinTriangle1(p[3],p[4],p[5],p[2])){
            cout << "contain" << endl;
            continue;
        }
        cout << "disjoint" << endl;
    }
    return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值