描述:
线段相交有两种情形:一种是“规范相交”,另一种是“非规范相交”。规范相交是指两条线段恰有唯一一个不是端点的公共点。即如果一条线段的端点在另一条线段上则不视为相交。如果两条线段有部分重合,也不视为相交。而非规范相交则把以上两种情况都视为相交。如下图所示:
规范相交认为a,b两种情况都是不相交的,而非规范相交认为a,b两种情况都是相交的。
本题要求判断两条线段是否相交。如果是规范相交则输出YES,并输出交点坐标,如果是非规范相交则只需输出YES,如果不相交则输出NO。
输入:
输入有多组数据,T表示输入数据的组数。每组测试数据有两行第一行输入一条线段的两个端点的坐标,第二行输入另一个线段的两个端点的坐标。
输出:
对于每组测试数据,输出一行。如果是规范相交则输出YES,并输出交点坐标(小数点后面保留3位),如果是非规范相交则只需输出YES,如果不相交则输出NO。
样例输入:
4
0 0 1 1
0 1 1 0
0 0 2 2
2 2 3 3
0 0 2 2
1.5 1.5 3 3
0 0 1 1
2 2 3 3
样例输出:
YES (0.500,0.500)
YES
YES
NO
题目分析:两条线段首先有两种情况:平行或不平行。如果平行,再判断两条线段的端点是否在另一条端点上,如果在则共线,即非规范相交,不在就只是平行;如果不平行,此时分为两种情况,因为是线段,所以有可能相交,有可能只是相离;相交还有一种特殊情况,就是线段1的端点在线段2上,此时也为非规范相交。
相交时可以先把两条线段所在直线的方程写出来,再进行联立,即可得出两个斜率的表达公式。
代码示例:
#include<iostream>
using namespace std;
struct point{
double x,y;
}ans;
bool judge1(point a,point b) //判断两个点是否相等,因为精度问题,所以尽量避开用=
{
return a.x!=b.x||a.y!=b.y;
}
bool judge2(point a1,point a2,point p)
{
if((p.x-a1.x)*(a2.y-a1.y)==(a2.x-a1.x)*(p.y-a1.y) //叉积相减是否为零,这里改为判断左右两式是否相等
&&min(a1.x,a2.x)<=p.x&&p.x<=max(a1.x,a2.x) //判断p是否在线段a1a2上
&&min(a1.y,a2.y)<=p.y&&p.y<=max(a1.y,a2.y))
return true;
return false;
}
int judge3(point a1,point a2,point b1,point b2)
{
if((a2.y-a1.y)*(b2.x-b1.x)!=(b2.y-b1.y)*(a2.x-a1.x)) //叉积
return 0;
if(judge2(a1,a2,b1)||judge2(a1,a2,b2)||judge2(b1,b2,a1)||judge2(b1,b2,a2))
return 1;
return 2;
}
int judge4(point a,point b,point c,point d)
{
if(!(min(a.x,b.x)<=max(c.x,d.x)&&min(c.x,d.x)<=max(a.x,b.x)
&&min(a.y,b.y)<=max(c.y,d.y)&&min(c.y,d.y)<=max(a.y,b.y)))
return false;
double k1=((c.x-a.x)*(d.y-c.y)-(c.y-a.y)*(d.x-c.x))/((b.x-a.x)*(d.y-c.y)-(d.x-c.x)*(b.y-a.y)); //斜率1
double k2=((a.x-c.x)*(b.y-a.y)+(c.y-a.y)*(b.x-a.x))/((d.x-c.x)*(b.y-a.y)-(b.x-a.x)*(d.y-c.y)); //斜率2
if(k1>=0&&k1<=1&&k2>=0&&k2<=1)
{
ans.x=a.x+k1*(b.x-a.x);
ans.y=a.y+k1*(b.y-a.y);
return true;
}
return false;
}
int main()
{
int t;
scanf("%d",&t);
while(t--)
{
point a1,a2,b1,b2;
scanf("%lf%lf%lf%lf",&a1.x,&a1.y,&a2.x,&a2.y);
scanf("%lf%lf%lf%lf",&b1.x,&b1.y,&b2.x,&b2.y);
if(judge3(a1,a2,b1,b2)==1)
puts("YES");
else if(judge3(a1,a2,b1,b2)==2)
puts("NO");
else
{
if(judge4(a1,a2,b1,b2))
{
printf("YES");
if(judge1(ans,a1)&&judge1(ans,a2)&&judge1(ans,b1)&&judge1(ans,b2))
printf(" (%.3f,%.3f)",ans.x,ans.y);
puts("");
}
else
puts("NO");
}
}
return 0;
}