做题小结
题目
线段相交
时间限制 (普通/Java):1000MS/3000MS 运行内存限制 :65536KByte
总提交 :356 测试通过 :77
描述
你将判断给定线段 L1,L2 是否相交 , 其中L1 表示为s1x,s1y,e1x,e1y, L2表示为s2x,s2y,e2x,e2y
输入
多组数据输入,每组一行,每组八个浮点数, s1x,s1y,e1x,e1y,s2x,s2y,e2x,e2y
输出
相交则输出 yes否则输出no
样例输入
0 1 2 1 1 0 1 2
1 1 2 2 3 3 4 4
样例输出
yes
no
算法
这一类的几何题目,可以先想象满足题目条件有哪几种情况。例如这道题目说的是线段相交,其实在一个二维平面上,线段相交就只有如下三种情况:
线段相交有三种可能性:
1)两个线段的四个点均分布在另外一条线段的两端;
2)一个线段的某一个端点在另一条线段上;
3)两个线段重合,一个长一个短;
显然,我们需要判断一个点在一条线段的左边,右边,还是正好在上边。这里就需要一个函数,返回就是点和线段的位置关系。
具体而言,对于情况 1)我们需要分别判断Line1的两点是否在 Line2的两边,以及Line2的两点是否在 Line1的两边;
对于情况 2)我们需要判断一个点是否在另一个线段上;情况 3)我们需要判断两个线段共线,然后一个线段的两点均在另一个线段的内部,也就是 x坐标位于之间。
代码如下:
#include<iostream>
using namespace std;
int RightOrLeft(double sX, double sY, double L1X, double L1Y, double L2X, double L2Y)
{
double difference=(sX-L1X)*(L2Y-L1Y)-(sY-L1Y)*(L2X-L1X);
if (difference>0)
return 1;
if(difference<0)
return -1;
if(difference==0)
{
if( (sX<L1X&&sX<L2X) || (sX>L1X&&sX>L2X)) //co-line yet not inside
return 0;
else
return 100; //inside the line segment
}
return 100000;
}
int main()
{
double fir1X, fir1Y, fir2X, fir2Y;
double sec1X, sec1Y, sec2X, sec2Y;
// int flag1, flag2;
// freopen("test.txt", "r", stdin);
while(cin>>fir1X>>fir1Y>>fir2X>>fir2Y>>sec1X>>sec1Y>>sec2X>>sec2Y)
{
int flag1=RightOrLeft(sec1X, sec1Y, fir1X, fir1Y, fir2X, fir2Y);
int flag2=RightOrLeft(sec2X, sec2Y, fir1X, fir1Y, fir2X, fir2Y);
int flag3=RightOrLeft(fir1X, fir1Y, sec1X, sec1Y, sec2X, sec2Y);
int flag4=RightOrLeft(fir2X, fir2Y, sec1X, sec1Y, sec2X, sec2Y);
// cout<<flag1<<' '<<flag2<<' '<<flag3<<' '<<flag4<<endl;
if(flag1==100
||flag2==100
||flag3==100
||flag4==100) //exist one point in the line segment
{
cout<<"yes"<<endl;
continue;
}
if( (flag1*flag2<0) && (flag3*flag4<0) )
{
cout<<"yes"<<endl;
continue;
}
if(flag1+flag2==0
&& flag3+flag4==0)
{
if( (fir1X<sec1X&&fir1X<sec2X&&fir2X>sec1X&&fir2X>sec2X)
||(sec1X<fir1X&&sec1X<fir2X&&sec2X>fir1X&&sec2X>fir2X) )
{
cout<<"yes"<<endl;
continue;
}
}
cout<<"no"<<endl;
}
return 0;
}