第八届福建省大学生程序设计竞赛 FZU 2273 Triangles (计算几何)
题目原文:http://acm.fzu.edu.cn/problem.php?pid=2273
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
Sample Output
题目大意:给定两个三角形六个顶点,判断两个三角形的关系(相交、相离、包含)
解题思路:
(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;
}
上一篇: Triangles FZU - 2273
下一篇: C#计算三角形面积