1605 计算几何:线段相交(快速排斥实验和跨立实验)

计算几何:线段相交
Time Limit(Common/Java):1000MS/3000MS          Memory Limit:65536KByte

Description

         线段相交测试在计算几何中是经常用到的,给定线段P1P2(P1和P2是线段的两端点,且不重合)、P3P4(P3和P4是线段的两端点,且不重合),判断P1P2和P3P4是否相交。P1P2和P3P4不重合,即指只存在一个点P,它既落在P1P2上又落在P3P4上(含线段的端点)。 

Input

输入数据有多组,第一行为测试数据的组数N,下面包括2N行,每组测试数据含2行,第一行为P1P2的坐标值,第二行为P3P4的坐标值,比如下面的数据
1
0 0 1 1
2 2 3 3
表示P1、P2、P3、P4的坐标分别为:P1(0,0),P2(1,1),P3(2,2),P4(3,3)

Output

判断每组数据中的线段P1P2和P3P4是否相交,如果相交输出YES,否则输出NO。每组数据输出占一行。

Sample Input

1
0 0 1 1
2 2 3 3

Sample Output

NO

Hint

两线段相交分为“规范相交”和“非规范相交”。 “规范相交”指的是两条线段恰有唯一一个不是端点的公共点;而如果一条线段的一个端点在另一条线段上,或者两条线段部分重合,则视为“非规范相交”,本题是“非规范相交”。 

定义点坐标类型时需用double


题目比较简洁,一共给出四个点,共形成两条线,判断这两条线是否相交。

判断两线段是否相交:


首先要知道,我们一定要先通过了快速排斥试验我们才能继续判断是否两条线相交,如果快速排斥试验都没能通过,那么这两条线是一定不会相交的。

[cpp]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. //快速排斥试验  
  2. if(min(a.x,b.x)>max(c.x,d.x)||min(a.y,b.y)>max(c.y,d.y)||min(c.x,d.x)>max(a.x,b.x)||min(c.y,d.y)>max(a.y,b.y))  
  3. return 0;  
接下来继续判断两条线是否相交:如果c,d两点在线段ab两端。并且a,b两点,在线段cd两端,那么就能说明两条直线相交。并且我们知道,向量叉乘可以判断一个线段在另一个线段的顺时针方向还是逆时针方向,如果cb和bd在ab的相反方向。也就是说向量叉乘的结果一个是正,一个是负。叉乘的值相乘如果是个负值,那就说明一定是cd在ab的两端了,同理,为了避免个别情况,也要判断一下ab在cd两端:

[cpp]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. u=(c.x-a.x)*(b.y-a.y)-(b.x-a.x)*(c.y-a.y);//c.b.a//u的正负表示bc在ab的顺时针方向还是逆时针方向.  
  2.  v=(d.x-a.x)*(b.y-a.y)-(b.x-a.x)*(d.y-a.y);//d.b.a//同理  
  3.  w=(a.x-c.x)*(d.y-c.y)-(d.x-c.x)*(a.y-c.y);//a.d.c  
  4.  z=(b.x-c.x)*(d.y-c.y)-(d.x-c.x)*(b.y-c.y);//b.d.c  
  5.  return (u*v<=0.00000001 && w*z<=0.00000001);  


AC代码:

#include <iostream>
using namespace std;
const double eps=1e-6;
struct point
{   
	double x,y; 
};
   double min(double a, double b) { return a < b ? a : b; } 
   double max(double a, double b) { return a > b ? a : b; } 
   bool inter(point a, point b, point c, point d)
{ 
  if(min(a.x, b.x) > max(c.x, d.x) || min(a.y, b.y) > max(c.y, d.y) || min(c.x, d.x) > max(a.x, b.x) || min(c.y, d.y) > max(a.y, b.y) )
    return 0; 
    double h, i, j, k; 
   h = (b.x - a.x) * (c.y - a.y) - (b.y - a.y) * (c.x - a.x); 
   i = (b.x - a.x) * (d.y - a.y) - (b.y - a.y) * (d.x - a.x); 
   j = (d.x - c.x) * (a.y - c.y) - (d.y - c.y) * (a.x - c.x); 
   k = (d.x - c.x) * (b.y - c.y) - (d.y - c.y) * (b.x - c.x); 
   return h * i <= eps && j * k <= eps; 
} 
int main()
{   
     point a,b,c,d;
	 double s;
	 int t;
      cin>>t;
  while(t--)
  { 
     cin>>a.x>>a.y>>b.x>>b.y>>c.x>>c.y >>d.x>>d.y;
     if(inter(a,b,c,d)==0)
	 cout<<"NO"<<endl;
     else cout<<"YES"<<endl;
    }
    return 0;
}


评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值