“蔚来杯“2022牛客暑期多校训练营4 M题: Monotone Chain

该博客介绍了如何判断多边形链是否对于某个射线是单调的。通过分析线段之间的角度关系,确定射线的方向应该在哪些范围内,最后检查这些范围是否有交集来得出结论。提供的参考代码使用C++实现,通过叉乘判断向量方向并寻找交集。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

M题: Monotone Chain

原题链接:https://ac.nowcoder.com/acm/contest/33189/M

题目大意

多边形链由一系列相连的线段构成,可以表示为一系列线段的端点 {A1,A2,...,An}\{A_1,A_2,...,A_n\}{A1,A2,...,An}

给定射线 La,b={a+λb∣λ∈R}L_{a,b}=\{a+\lambda b|\lambda \in \R \}La,b={a+λbλR} ,定义多边形链 C={A1,A2,...,An}C=\{A_1,A_2,...,A_n\}C={A1,A2,...,An} 单调于射线 La,bL_{a,b}La,b ,当且仅当:

  • ∀1≤i<j≤n,(OAi−a)⋅b≤(OAj−a)⋅b\forall 1\le i< j\le n,(OA_i-a)⋅b \le(OA_j-a)⋅b∀1i<jn,(OAia)b(OAja)b
    其中 OAiOA_iOAi 表示 AiA_iAi 的坐标, ⋅⋅ 表示向量的点乘

给定 nnn 个点的多边形链 CCC ,判断是否存在射线 La,bL_{a,b}La,b 使得多边形链 CCC 单调于射线 La,bL_{a,b}La,b ,若有则求出任意解。

题解

∀v⃗=AiAi+1(1≤i<n)\forall \vec{v}=A_iA_{i+1}(1\le i<n)v=AiAi+1(1i<n) ,发现射线 La,bL_{a,b}La,b 的方向与 v⃗\vec{v}v 的夹角应不超过 90°90°90° ,换句话说,射线的方向都在以 v⃗\vec{v}v 为角平分线的平角范围内。
不妨对所有的 v⃗\vec{v}v 求出可行的射线方向范围,然后验证是否有交集即可
当表示方向的范围时,可以用向量来保存两个边界(逆时针的最大方向与顺时针的最大方向),然后用叉乘判断交集是否存在即可。

参考代码

#include<bits/stdc++.h>
using namespace std;

template<class T>inline void read(T&x){//快读
	char c,last=' ';
	while(!isdigit(c=getchar()))last=c;
	x=c^48;
	while(isdigit(c=getchar()))x=(x<<3)+(x<<1)+(c^48);
	if(last=='-')x=-x;
}

#define ll long long
const int MAXN=1e5+5;
int n;

struct Point{//向量表示
	ll x,y;
}P[MAXN];

ll operator^(Point&a,Point&b){//叉乘,用于判断方向
	return a.x*b.y-a.y*b.x;
} 

int main()
{
	read(n);
	for(int i=1;i<=n;++i)read(P[i].x),read(P[i].y);
	bool ok=0;//0表示还没有初始化
	Point L={1,1},R;//若所有点都重合时,输出0 0 1 1作为答案
	for(int i=1;i<n;++i){
		Point p={P[i+1].x-P[i].x,P[i+1].y-P[i].y},l,r;//求出折线当前段
		if(p.x==0&&p.y==0)continue;//如果两点重合,跳过
		l={-p.y,p.x},r={p.y,-p.x};//l表示以当前段作为角平分线时的逆时针边界,r表示顺时针边界
		if(!ok){//还没有初始化,则将当前范围直接作为交集
			ok=1;
			L=l,R=r;
			continue;
		}
		if((l^R)>0&&(r^L)<0){//出现无交集的情况,即无解
			puts("NO");exit(0);
		}
		if((l^L)>0)L=l;//逆时针边界缩小
		if((r^R)<0)R=r;//顺时针边界缩小
	}
	puts("YES");
	cout<<"0 0 "<<L.x<<' '<<L.y<<'\n';//因为是闭区间,直接取边界作为答案即可
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值