NuptOJ1041线段相交——向量积

74 篇文章 0 订阅

线段相交

Time Limit(Common/Java):1000MS/3000MS          Memory Limit:65536KByte
Total Submit:328            Accepted:71

Description

你将判断给定线段L1L2是否相交其中L1表示为s1x,s1y,e1x,e1yL2表示为s2x,s2y,e2x,e2y

Input

多组数据输入,每组一行,每组八个浮点数,s1x,s1y,e1x,e1y,s2x,s2y,e2x,e2y

Output

相交则输出yes否则输出no

Sample Input

0 1 2 1 1 0 1 2
1 1 2 2 3 3 4 4

Sample Output

yes
no

Source

NUAA


分析:线段相交的判断用向量积做比较方便。但是逻辑一定要清晰。大一学的线性代数记忆已经不深刻了。遇到了一些小问题。当然还可以有其他做法,比如构造方程判断是否有解等等。

向量积回顾:

|向量a×向量b|=|a||b|sinθ在这里θ表示两向量之间的角夹角(0° ≤ θ ≤ 180°),它位于这两个矢量所定义的平面上。

关键点在于求得的向量积的方向问题。这就取决于向量a与向量b的夹角。(这里的向量写的时候在字母上面加上向右的箭头)。


一般的直接比较两条线段的x轴最大与最小值 以及 y轴的最大与最小值可以直接判断是否相交。但是出现以下情况(显然这2条线段是不相交的):


这就需要向量积(叉积)发挥作用了!

向量ab(b.x-a.x,b.y-a.y)和向量ac的叉积=ab的长度*ac的长度*sin(从ab到ac转过的角度)=(b.x-a.x)*(c.y-a.y) - (b.y-a.y)*(c.x-a.x)。

所以方向是垂直于纸面向外(想起物理了 :))。

这里要非常小心叉积的顺序。顺序不一样,它们的夹角也不一样。夹角总是从前面的向量逆时针转到后面的向量的!!!


所以只要保证 ab x ac 得到的向量积的方向与ad x ab一致,表达式即为它们的乘积 >= 0。

同理:cd x ca (向量积)的方向与 cb x cd(向量积) 的方向也应该保持一致。

上图中 cd 与 ca 的向量积小于0,cb 与 cd 的向量积大于0,不符合要求,所以不相交。

#include<stdio.h>

//线段相交——向量积

struct point
{
	double x;
	double y;
};
double min(double x, double y)
{
	return x<y ? x : y;
}
double max(double x, double y)
{
	return x>y ? x : y;
}

double mul(point a, point b, point c) // AB->(向量) x AC->(向量) 叉积 
{
	return (b.x-a.x)*(c.y-a.y) - (b.y-a.y)*(c.x-a.x);
}

bool judge(point a, point b, point c, point d)
{
	return ( (max(a.x, b.x) >= min(c.x, d.x)) && 
		     (max(c.x, d.x) >= min(a.x, b.x)) &&
		     (max(a.y, b.y) >= min(c.y, d.y)) &&
			 (max(c.y, d.y) >= min(a.y, b.y)) &&
			 (mul(a, b, c) * mul(a, d, b) >= 0) &&
			 (mul(c, d, a) * mul(c, b, d) >= 0) );
}

int main()
{
	point a, b, c, d;
	while(scanf("%lf%lf%lf%lf%lf%lf%lf%lf",&a.x,&a.y,&b.x,&b.y,&c.x,&c.y,&d.x,&d.y) != EOF)
	{
		if(judge(a, b, c, d) == true)
			printf("yes\n");
		else
			printf("no\n");
	}
	return 0;
}



  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值