TZOJ3348: 线段相交Ⅲ

题意:

线段相交有两种情形:一种是“规范相交”,另一种是“非规范相交”。规范相交是指两条线段恰有唯一一个不是端点的公共点。即如果一条线段的端点在另一条线段上则不视为相交。如果两条线段有部分重合,也不视为相交。而非规范相交则把以上两种情况都视为相交。

给出两条线段,若它们相交则输出YES,为规范相交的情况还要额外输出交点坐标,不相交输出NO。

题解:

向量叉乘简单地可以求出一个以两平面向量为临边的平行四边形的面积。同时若AxB>0,说明B在A的顺时针方向,AxB>0说明B在A的逆时针方向(AxB=0说明两向量方向相同)。

对于该问题先判断两线段是否平行,记四个点分别为A,B,C,D,线段分别为AB,CD。可以通过计算ABxCD是否为0判断两线段(向量)是否平行。

对于线段平行的情况:不可能做到规范相交,仅需判断是否为非规范相交。证明平行直线AB,CD非规范相交可以通过证明AB,CD共线且AB,CD在x轴上的投影是否相交。共线:ABxAC=0(AB//CD且AB//AC可以明显发现AB,CD共线),在x轴上投影有交集:max(Ax,Cx)<=min(Bx,Dx)。对于以上两个条件有任意一个不满足都为不相交。

对于线段不平行的情况:先证明相交,可以通过跨立实验证明,对于ABxAC与ABxAD,若他们异号,则说明点C与点D在直线AB异侧,再证明点A,B在直线CD异侧则两线段规范相交。特别的,若有一组例如ABxAC=0说明点C在直线AB上,同时没有被证明他们不相交(同号)的情况下说明他们非规范相交。对于其他情况(出现同号)为不相交。

对于已经证明规范相交求交点:这位大佬写的挺好的,我基本照着这个思路写的叉乘(叉积)求两向量的交点?一张图就够了!——全网独家_向量求交点_吾儿沛安的博客-CSDN博客

#define _CRT_SECURE_NO_WARNINGS
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
#include<vector>
using namespace std;
typedef long long LL;
typedef pair<int, int> PII;
const LL N = 1e3 + 10, MOD = 1e9 + 7, INF = 0x3f3f3f3f;
const double eps = 1e-6;
struct vec
{
	double x, y;
};
vec get_vec(vec a, vec b)
{
	return { b.x - a.x,b.y - a.y };
}
vec add(vec a, vec b)
{
	return { a.x + b.x,a.y + b.y };
}
double cross(vec a,vec b)
{
	return a.x * b.y - a.y * b.x;
}
void solve()
{
	vec p[5];
	for (int i = 1; i <= 4; ++i)
		scanf("%lf%lf", &p[i].x, &p[i].y);
	vec v1 = get_vec(p[1], p[2]), v2 = get_vec(p[3], p[4]);
	if (cross(v1, v2))//判断是否平行
	{
		double c1 = cross(v1, get_vec(p[1], p[3]));
		double c2 = cross(v1, get_vec(p[1], p[4]));
		double c3 = cross(v2, get_vec(p[3], p[1]));
		double c4 = cross(v2, get_vec(p[3], p[2]));
		//跨立实验
		if (c1 * c2 > eps || c3 * c4 > eps)//不相交
			printf("NO\n");
		else if (fabs(c1 * c2) < eps || fabs(c3 * c4) < eps)//一线段端点与另一线段相交
			printf("YES\n");
		else
		{
			double s1 = cross(get_vec(p[1], p[4]), v2), s2 = cross(v1, v2);
			double k = fabs(s1 / s2);
			vec t = { k * v1.x,k * v1.y }, po = add(p[1], t);
			printf("YES (%.3f,%.3f)\n", po.x, po.y);
		}
	}
	else
	{
		//共线且在x轴上的投影有相交的部分则俩线段相交了
		if (fabs(cross(v1, get_vec(p[1], p[3]))) < eps && max(p[1].x, p[3].x) - eps <= min(p[2].x, p[4].x))
			printf("YES\n");
		else
			printf("NO\n");
	}
}
int main()
{
	int T = 1;
	scanf("%d", &T);
	while (T--)
	{
		solve();
	}
	return 0;
}

写了一堆bug,题还有点读假题,改了好久才A...

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值