FZUOJ-2273 Triangles
Problem 2273 Triangles
Accept: 109 Submit: 360
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
Source
第八届福建省大学生程序设计竞赛-重现赛(感谢承办方厦门理工学院)链接:http://acm.fzu.edu.cn/contest/problem.php?cid=156&sortid=2
题意:给出两个三角形A,B的三个点的坐标,判断这两个三角形的位置关系,分为包含(contain),相交(intersect),不相交(disjoint)三种关系,特别的,边或者点重合也属于相交;
思路:可以先判断A的某一条边是否和B的某一条边相交(包括点重合和边重合)来判断相交关系,然后可以根据三角形A(B)的一个定点是否在三角形B(A)内来判断包含关系;如不满足前两种关系,则三角形A,B便满足第三种关系;判断某一点是否在三角形内可以用面积法来判断,若点P在三角形内部(包括边上),则有S(ABC)=S(ABP)+S(APC)+S(BPC);否则有S(ABC)小于三个小三角形面积之和;三角形的面积可以利用向量积(叉积)来做,S=|ABxAC|/2;
ps:(如果下面的分析有误,欢迎指出,代码有参考模板)
#include<iostream> #include<cstring> #include<cstdio> #include<cmath> #define eps 1e-8 #define zero(x) (((x)>0?(x):(-x))<eps) using namespace std; struct point{double x,y;}; struct triangle{point a,b,c;}; ///计算叉积 /** 设向量A=p1-p0,B=p2-p0; | i j k | AxB=| p1.x-p0.x p1.y-p0.y 0 | | p2.x-p0.x p2.y-p0.y 0 | */ double xmult(point p1,point p2,point p0){ return (p1.x-p0.x)*(p2.y-p0.y)-(p2.x-p0.x)*(p1.y-p0.y); } ///判断三点共线 /** 若三点共线 设向量A=p1-p0,B=p2-p0; |AxB|=|A||B|sin<A,B>,又三点共线,所以<A,B>=0,所以|AxB|=0; */ int dots_inline(point p1,point p2,point p3){ return zero(xmult(p1,p2,p3)); } ///判断两点在线段同侧 /** 设向量 A=l2-l1,B=p2-l1,C=p1-l1; 由右手定则可以得出,若p1,p2两点同侧,则|AxB|与|AxC|同正负; 若p1或p2在线段上,则|AxC|或|AxB|等于0 */ int same_side(point p1,point p2,point l1,point l2){ return xmult(l1,p1,l2) * xmult(l1,p2,l2) > eps; } ///判断点是否在线上,包括端点 /** 1.先判三点共线; 2.再判点是否在线段上,如果在,则两个端点的横坐标与该点的横坐标(纵坐标)之差的积小于或者等于零; */ int dot_online_in(point p,point l1,point l2){ return zero(xmult(p,l1,l2))&&(l1.x-p.x)*(l2.x-p.x) < eps && (l1.y-p.y)*(l2.y-p.y) < eps; } ///判断两线相交,包括部分重合和点重合 /** 1.先判是否共线,如果不共线,看其中一条边的两个端点是否在另一条线段的两侧; 2.判断点是否在线段上; */ int intersect_in(point u1,point u2,point v1,point v2){ if(!dots_inline(u1,u2,v1)||!dots_inline(u1,u2,v2)) return !same_side(u1,u2,v1,v2) && !same_side(v1,v2,u1,u2); return dot_online_in(u1,v1,v2)||dot_online_in(u2,v1,v2)||dot_online_in(v1,u1,u2)||dot_online_in(v2,u1,u2); } ///计算面积 /** S=|AxB|/2; */ double area_triangle(point p1,point p2,point p3){ return fabs(xmult(p1,p2,p3))/2; } ///判断点是否包含在三角形内部,包括三条边上 /** 大三角形与三个小三角形的面积之差是否为零 */ int dot_triangle_in(triangle p1,point p0){ return fabs(area_triangle(p1.a,p1.b,p1.c)-area_triangle(p1.a,p1.b,p0)-area_triangle(p1.a,p0,p1.c)-area_triangle(p0,p1.b,p1.c))<eps; } void solve_question(){ point a[3],b[3]; triangle A,B; for(int i=0;i<3;i++) cin >> a[i].x >> a[i].y; for(int i=0;i<3;i++) cin >> b[i].x >> b[i].y; A = (triangle){a[0],a[1],a[2]}; B = (triangle){b[0],b[1],b[2]}; for(int i=0;i<3;i++) for(int j=0;j<3;j++) if(intersect_in(a[i],a[(i+1)%3],b[j],b[(j+1)%3])) { printf("intersect\n");return;} if(dot_triangle_in(A,b[0]) || dot_triangle_in(B,a[0])) printf("contain\n"); else printf("disjoint\n"); } int main(){ int T; scanf("%d",&T); while(T--){ solve_question(); } }