题目:http://www.51nod.com/onlineJudge/questionCode.html#!problemId=1264
本来想用斜率来算,后来觉得要分太多情况,上网发现用快速排斥+跨立就能做
快速排斥的意思是当两条线段分别构成的矩形范围没有相交,那么两直线肯定没没有交点,如下图
如何判断两个矩形相交?一种错误的思路是一个矩形中的点在另一个矩形里,单如果是十字相交的矩形就不成立
我的方法是找到两个矩形的中心点C1,C2,设两个矩形的宽和高分别为W1,H1,W2,H2
那么只要满|C1.x-C2.x|<=(W1+W2)/2 && |C1.y-C2.y|<=(H1+H2)/2就是相交
bool MBR(rec a1,rec a2) { p c[3]; double w[3],h[3]; c[1].x=(a1.left.x+a1.right.x)/2; c[1].y=(a1.left.y+a1.right.y)/2; c[2].x=(a2.left.x+a2.right.x)/2; c[2].y=(a2.left.y+a2.right.y)/2; w[1]=a1.right.x-a1.left.x; w[2]=a2.right.x-a2.left.x; h[1]=a1.left.y-a1.right.y; h[2]=a2.left.y-a2.right.y; if(abs(c[1].x-c[2].x)<=(w[1]+w[2])/2&&abs(c[1].x-c[2].x)<=(w[1]+w[2])/2) return true; return false; }
排除必然不相交的情况后再来看哪些情况相交,这里用到跨立
跨立即一向量跨过另一向量,如下图只需AC向量和AD向量在AB向量两侧,同时CA向量和CB向量在CD向量的两侧即可证明
怎么实现在两侧?用向量叉乘(ACxAB)·(ABXAD)<=0即可说明AC与AD在AB两侧(要注意考虑重合的情况)
以下是完整代码
#include<iostream> #include<algorithm> #include<cmath> using namespace std; struct p { double x,y; }; struct vec { double x,y; }; struct rec { p left,right; }; rec rectangle(p a1,p a2) { rec r; r.left.x=min(a1.x,a2.x); r.left.y=max(a1.y,a2.y); r.right.x=max(a1.x,a2.x); r.right.y=min(a1.y,a2.y); return r; } vec vector(p a1,p a2) { vec v; v.x=a2.x-a1.x; v.y=a2.y-a1.y; return v; } double vec_pro(vec v1,vec v2) { return v1.x*v2.y-v1.y*v2.x; } bool MBR(rec a1,rec a2) { p c[3]; double w[3],h[3]; c[1].x=(a1.left.x+a1.right.x)/2; c[1].y=(a1.left.y+a1.right.y)/2; c[2].x=(a2.left.x+a2.right.x)/2; c[2].y=(a2.left.y+a2.right.y)/2; w[1]=a1.right.x-a1.left.x; w[2]=a2.right.x-a2.left.x; h[1]=a1.left.y-a1.right.y; h[2]=a2.left.y-a2.right.y; if(abs(c[1].x-c[2].x)<=(w[1]+w[2])/2&&abs(c[1].x-c[2].x)<=(w[1]+w[2])/2) return true; return false; } int main() { int t; cin>>t; while(t--) { rec r[3]; p a[5]; bool is_intersect=true,need_judge=true; for(int i=1;i<=4;i++) cin>>a[i].x>>a[i].y; r[1]=rectangle(a[1],a[2]); r[2]=rectangle(a[3],a[4]); if(!MBR(r[1],r[2])) { is_intersect=false; need_judge=false; } if(need_judge) { vec AB=vector(a[1],a[2]); vec AC=vector(a[1],a[3]); vec AD=vector(a[1],a[4]); vec CA=vector(a[3],a[1]); vec CB=vector(a[3],a[2]); vec CD=vector(a[3],a[4]); if(vec_pro(AB,AC)*vec_pro(AB,AD)<=0&&vec_pro(CD,CA)*vec_pro(CD,CB)<=0) is_intersect=true; else is_intersect=false; } if(is_intersect) cout<<"Yes"<<endl; else cout<<"No"<<endl; } }