目录
题目
题目描述
输入线段AB、CD的两端点,判断两线段是否相交(包含端点)
输入格式
有多组数据,每组数据两行,第一行四个整数,分别表示A、B两点坐标,第二行四个整数,分别表示C、D两点坐标
输入样例
0 1 1 1
1 0 2 1
1 0 2 1
0 1 2 0
0 0 0 1
1 0 0 0
输出样例
no
yes
yes
代码
#include<iostream>
#include<algorithm>//max(),min()
using namespace std;
int main()
{
int x1,y1,x2,y2,x3,y3,x4,y4;
int a,b,c,d;//表示向量叉积
while(cin>>x1>>y1>>x2>>y2)
while(cin>>x3>>y3>>x4>>y4)
{
a = (x2 - x1) * (y3 - y1) - (y2 - y1) * (x3 - x1);//向量AB * AC的叉积
b = (x2 - x1) * (y4 - y1) - (y2 - y1) * (x4 - x1);//AB * AD
c = (x4 - x3) * (y1 - y3) - (y4 - y3) * (x1 - x3);//CD * CA
d = (x4 - x3) * (y2 - y3) - (y4 - y3) * (x2 - x3);//CD * CB
if(max(x1,x2) < min(x3,x4) || max(x3,x4) < min(x1,x2)
|| max(y1,y2) < min(y3,y4) || max(y3,y4) < min(y1,y2))
cout<<"no"<<endl;
else if(a * b <= 0 && c * d <= 0)
cout<<"yes"<<endl;
else
cout<<"no"<<endl;
break;//否则一直在内层while循环
}
return 0;
}
该代码oj上Accepted,复制直接可用
分析
1,基础知识
点乘:也叫数量积,表示表示一个向量在另一个向量方向上投影的长度,点积结果是标量
叉乘:向量积,叉积结果是向量
2,基础思路(本题叉乘不考虑Z轴)
叉积的一个非常重要的性质就是,它的正负表示两向量的顺逆时针关系(本题代码的基础)
已知两向量AB,AC
AB * AC > 0,AB在AC的顺时针方向(注意是前在后的顺时针方向,这里的顺序很重要)
AB * AC < 0,AB在AC的逆时针方向
AB * AC = 0,AB与AC共线,正向或者反向
比如设AB(2,2), AC(2,1),AB * AC叉积为2 - 4 < 0,且容易看出AB在AC的逆时针方向
3,平面直角坐标系里的叉乘公式
a(x1, y1), b(x2, y2), a * b(叉乘) = x1 * y2 - y1 * x2(交叉相乘的相减)(注意顺序)
4,分类讨论
第一,先利用最大最小x,y值排除两线段肯定不相交的情况(前提),否则可能共线(叉乘为0)
第二, 代码中a,b异号且c,d异号,即两对叉积分别为相反数,表示一个顺时针一个逆时针
第三,一条线段端点在另一线段上,则(a == 0 || b == 0) && (c*d < 0) 或者 (a * b < 0) && (c == 0 || d == 0),联立第二条分类讨论,满足代码a * b <= 0 && c * d <= 0