欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

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

程序员文章站 2022-04-01 16:08:48
...

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

Problem B Triangles

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

第八届福建省大学生程序设计竞赛 FZU 2273 Triangles (计算几何) 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.)

第八届福建省大学生程序设计竞赛 FZU 2273 Triangles (计算几何) 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

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

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

第八届福建省大学生程序设计竞赛 FZU 2273 Triangles (计算几何) 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

第八届福建省大学生程序设计竞赛 FZU 2273 Triangles (计算几何) 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;
}


相关标签: ACM 计算几何