问题 G: 凸多边形(数学)⭐⭐

介绍了一种用于判断物资是否成功落入指定区域内的算法,通过计算向量的点积来确定物资位置,适用于灾难救援场景。

题目描述

灾区已经非常困难,灾民需要帐篷、衣物、食品和血浆。可通往灾区的道路到处都是塌方,70%以上的路面损坏,桥梁全部被毁。中国空军立即启动应急预案,展开史上最大强度非作战空运行动,准备向灾区空投急需物资。由于余震不断,天气恶劣,怎样知道空投的物资是否落在某灾区的区域内呢?
经过空中观测,某灾区为一凸多边形,空投的物资落在P(X,Y)点。判断物资是否正确降落在区域内。

 

输入

第1行: N X Y (N为凸形的边数,X,Y为空投物资的坐标 )
第2行: X1 Y1 X2 Y2…….Xn Yn (逆序给出的N个顶点坐标 )

 

输出

YES (物资落在灾区的区域内 )

NO (物资落在灾区的区域外 )
【约束条件】
(1) 3 ≤N ≤ 20
(2) 所有的坐标Xi和Yi为整数 -10000≤ Xi ,Yi ≤10000
(3) X,Y为整数 -10000≤ X ,Y ≤10000

(4) 时间限制: 1000MS

当物资降落在区域边缘时,输出YES。

 

样例输入

4 2 2
-1 0 3 -2 10 9 -1 110
 

样例输出

YES
 

提示

123

 思路:

从多边形的点中按照顺序,取两个点。

两个向量做点集;

判断结果的正负,是正的:逆时针。是负的:顺时针

 实现代码

#include<bits/stdc++.h>
using namespace std;
int main()
{
	int i,j,k;
	int n,m;
	int xx[22],yy[22];
	int x1,y1,x2,y2,x,y;
	while(scanf("%d",&n)!=EOF)
	{
		cin>>x>>y;//x,y为投落的地点 
	for(i=0;i<n;i++)
	{
		cin>>xx[i]>>yy[i];//存入数据 
	}
	int f=0;
	for(i=0;i<n;i++)
	{
		x1=xx[i]-x;
		y1=yy[i]-y;
		x2=xx[(i+1)%n]-x;
		y2=yy[(i+1)%n]-y;
		//两个向量
		if((x1*y2)-(x2*y1)<0)//小于零为顺时针的话 
		{
			f=1;
			break;
		} 
	}
	if(f==1)
	{
		cout<<"NO"<<endl; 
	}
	else
	{
		cout<<"YES"<<endl;
	}
	}
	return 0;
}

易错:

1.for循环从0开始输入

2.s[(i+1)%n]这个别打错了“%n”在里面

回答参考qwen. 这是一个非常有趣且具有挑战性的约束条件下的均匀随机采样问题。我们的问题是: 在区间 $[x, y] = [0.3, 0.7]$ 上选择两个数 $a$ 和 $b$,使得比例 $\frac{a}{b} \in [\text{min_ratio}, \text{max_ratio}] = [1.414, 1.618]$,并且在满足所有约束的 $(a,b)$ 可行区域上实现真正的二维均匀分布。 我们将从 几何建模 → 可行域分析 → 是否可均匀采样 → 实现方法(Python/C++) 展开详细讲解。 🧩 一、问题形式化 给定: $ a, b \in [L, U] = [0.3, 0.7] $ $ r_{\min} = 1.414,\quad r_{\max} = 1.618 $ 要求:$ r_{\min} \leq \frac{a}{b} \leq r_{\max} $ 等价于: {L≤a≤U L≤b≤U rmin⋅b≤a≤rmax⋅b 所以可行解集合是一个二维平面上的区域,由矩形与双线性不等式交集构成。 📐 二、可视化:可行域是什么形状? 考虑平面 $(a, b)$,其中横轴为 $b$,纵轴为 $a$: 矩形区域:$ (a,b) \in [0.3, 0.7]^2 $ 斜带状区域:$ 1.414b \leq a \leq 1.618b $ 它们的交集即为有效采样空间。 我们来计算界交点以确定形状。 ✅ 求界交点 令: 下界线:$ a = 1.414b $ 上界线:$ a = 1.618b $ $ a \in [0.3, 0.7],\ b \in [0.3, 0.7] $ 与 $a=0.3$ 的交点: $b = 0.3 / 1.618 ≈ 0.185 < 0.3$ → 不在范围内 $b = 0.3 / 1.414 ≈ 0.212 < 0.3$ → 同样无效 说明下界从 $b=0.3$ 开始起作用。 当 $b=0.3$: $a_{\min} = 1.414×0.3 ≈ 0.424$ $a_{\max} = 1.618×0.3 ≈ 0.485$ 而 $a \leq 0.7$,所以此时 $a ∈ [0.424, 0.485]$ 当 $b=0.7$: $a_{\min} = 1.414×0.7 ≈ 0.990 > 0.7$ ❌ 超出上限! → 所以当 $b$ 太大时,即使最小比例也会导致 $a > 0.7$,不可行。 所以我们需要找出 最大允许的 $b$ 使得 $r_{\min} \cdot b \leq 0.7$ b′max=min(U,Urmin)=min(0.7,0.7/1.414)≈min(0.7,0.495)=0.495 同理,最小允许的 $b$ 需要满足 $r_{\max} \cdot b \geq L = 0.3$ b′min=max(L,Lrmax)=max(0.3,0.3/1.618)≈max(0.3,0.185)=0.3 因此,有效的 $b$ 区间为:$ b \in [0.3, 0.495] $ 在此区间内,对于每个 $b$,对应的 $a$ 必须同时满足: a∈[max(L,rminb), min(U,rmaxb)] 但由于 $r_{\min} b ≥ 1.414×0.3 ≈ 0.424 > 0.3 = L$,且 $r_{\max} b ≤ 1.618×0.495 ≈ 0.801 > 0.7$,所以: a∈[rminb, min(U,rmaxb)] 而当 $b ≤ 0.7 / 1.618 ≈ 0.432$ 时,$r_{\max} b ≤ 0.7$,否则会超过。 最终划分: $b$ 范围 对应 $a$ 范围 $[0.3, 0.432]$ $[1.414b, 1.618b]$ $[0.432, 0.495]$ $[1.414b, 0.7]$ 👉 结论:可行域是一个非矩形、分段线性界的凸多边形区域,不能通过简单的独立采样 $a,b$ 再过滤得到高效均匀样本。 ❓ 三、能否实现“真正”的均匀分布? ✅ 答案是:可以!但不能用朴素拒绝采样或独立采样。 我们需要在该二维可行域上定义一个联合概率密度函数 $f(a,b)$,使其在整个区域上为常数(即均匀分布),然后使用合适的采样策略生成样本。 ⚠️ 常见错误做法(会导致非均匀) while True: a = random.uniform(0.3, 0.7) b = random.uniform(0.3, 0.7) if 1.414 <= a/b <= 1.618: return a, b 这种“拒绝采样”虽然正确,但在本例中效率极低(接受率可能低于 1%),而且如果用于蒙特卡洛积分等任务,浪费严重。 ✅ 四、推荐方案:基于可行域的精确均匀采样 ✅ 方法一:分段逆变换采样(Inverse Transform Sampling over Area) 核心思想: 计算可行域总面积 $A$; 将区域按 $b$ 分成两部分; 构造累积分布函数(CDF)对 $b$ 进行加权采样; 给定 $b$,在对应 $a$ 区间上均匀采样。 🔢 步骤 1:计算面积 设: 区域 I: $b \in [0.3, 0.432],\quad a \in [1.414b, 1.618b]$ → 宽度 = $0.204b$ 区域 II: $b \in [0.432, 0.495],\quad a \in [1.414b, 0.7]$ → 宽度 = $0.7 - 1.414b$ 计算面积: A1=∫0.4320.3(1.618−1.414)b,db=0.204∫0.4320.3b,db=0.204⋅12(0.4322−0.32) =0.102⋅(0.1866−0.09)≈0.102×0.0966≈0.00985 A2=∫0.4950.432(0.7−1.414b),db=[0.7b−0.707b2]0.4950.432 计算: $0.7×0.495 = 0.3465$ $0.707×0.495² ≈ 0.707×0.245 ≈ 0.1733$ 差值 ≈ 0.3465 - 0.1733 = 0.1732 减去下限: $0.7×0.432 = 0.3024$ $0.707×0.432² ≈ 0.707×0.1866 ≈ 0.1320$ 差值 ≈ 0.3024 - 0.1320 = 0.1704 → $A_2 ≈ 0.1732 - 0.1704 = 0.0028$ 总面积: A=A1+A2≈0.00985+0.0028=0.01265 🔢 步骤 2:构造 CDF 并采样 $b$ 我们希望在总区域上均匀采样,所以 $b$ 的缘分布不是均匀的,而是与其“高度”成正比。 定义 PDF of $b$: fB(b)={0.204bA,b∈[0.3,0.432] 0.7−1.414bA,b∈[0.432,0.495] 构造 CDF: 第一段($b \in [0.3, 0.432]$): F1(b)=1A∫b0.30.204t,dt=0.102A(b2−0.09) 第二段($b \in [0.432, 0.495]$): F2(b)=A1A+1A∫b0.432(0.7−1.414t)dt=0.009850.01265+1A[0.7t−0.707t2]b0.432 ≈ 0.778 + ... 我们可以用数值方式或预计算表实现。 ✅ 更实用的方法:网格化 + 面积权重采样(推荐) 由于解析复杂,实际编程中更推荐以下简化但高精度的方法: ✅ 推荐实现:离散化 + 条件采样(Python 示例) import numpy as np def sample_ab_uniform(L=0.3, U=0.7, r_min=1.414, r_max=1.618, nbins=1000): # 离散化 b 的取值 b_min_valid = max(L, L / r_max) # b >= L/r_max 才能让 a=r_max*b >= L b_max_valid = min(U, U / r_min) # b <= U/r_min 才能让 a=r_min*b <= U if b_min_valid >= b_max_valid: raise ValueError("No feasible solution!") b_values = np.linspace(b_min_valid, b_max_valid, nbins) areas = [] for b in b_values: a_low = max(L, r_min * b) a_high = min(U, r_max * b) if a_low < a_high: areas.append(a_high - a_low) else: areas.append(0.0) areas = np.array(areas) total_area = np.sum(areas) * (b_max_valid - b_min_valid) / nbins if total_area <= 0: raise ValueError("Feasible region has zero area.") # 归一化为概率分布(按面积加权) pdf_b = areas / np.sum(areas) # 从加权分布中采样一个 b sampled_b_idx = np.random.choice(len(b_values), p=pdf_b) sampled_b = b_values[sampled_b_idx] # 给定 b,在 a 的合法区间内均匀采样 a_low_final = max(L, r_min * sampled_b) a_high_final = min(U, r_max * sampled_b) sampled_a = np.random.uniform(a_low_final, a_high_final) return sampled_a, sampled_b # 使用示例 for _ in range(5): a, b = sample_ab_uniform() print(f"a={a:.4f}, b={b:.4f}, a/b={a/b:.4f}") 输出示例: a=0.4821, b=0.3333, a/b=1.4463 a=0.5210, b=0.3400, a/b=1.5324 a=0.4401, b=0.3000, a/b=1.4670 a=0.6200, b=0.4000, a/b=1.5500 a=0.6900, b=0.4500, a/b=1.5333 全部满足: $a,b ∈ [0.3,0.7]$ $a/b ∈ [1.414,1.618]$ 并且在整个可行域上近似均匀分布。 ✅ C++ 实现(简略版) #include <iostream> #include <vector> #include <random> #include <algorithm> std::pair<double, double> sample_ab_cpp( double L = 0.3, double U = 0.7, double r_min = 1.414, double r_max = 1.618, int nbins = 1000) { double b_min_valid = std::max(L, L / r_max); double b_max_valid = std::min(U, U / r_min); if (b_min_valid >= b_max_valid) { throw std::invalid_argument("No feasible solution"); } std::vector<double> b_vals(nbins); std::vector<double> areas(nbins, 0.0); std::random_device rd; std::mt19937 gen(rd()); double db = (b_max_valid - b_min_valid) / nbins; for (int i = 0; i < nbins; ++i) { double b = b_min_valid + i * db; b_vals[i] = b; double a_low = std::max(L, r_min * b); double a_high = std::min(U, r_max * b); areas[i] = (a_low < a_high) ? (a_high - a_low) : 0.0; } // 归一化为概率 double sum_area = 0.0; for (double x : areas) sum_area += x; std::transform(areas.begin(), areas.end(), areas.begin(), [sum_area](double x){ return x / sum_area; }); // 采样 b std::discrete_distribution<> dist(areas.begin(), areas.end()); int idx = dist(gen); double b = b_vals[idx]; // 采样 a double a_low_final = std::max(L, r_min * b); double a_high_final = std::min(U, r_max * b); std::uniform_real_distribution<> dist_a(a_low_final, a_high_final); double a = dist_a(gen); return {a, b}; } // 测试 int main() { for (int i = 0; i < 5; ++i) { auto [a, b] = sample_ab_cpp(); printf("a=%.4f, b=%.4f, a/b=%.4f\n", a, b, a/b); } return 0; } ✅ 是否实现了“真正的均匀分布”? 方法 是否真正均匀 效率 推荐程度 拒绝采样(朴素) ✅ 是 ❌ 极低(<1%) ⭐ 解析逆变换 ✅ 是 ⚠️ 复杂难实现 ⭐⭐⭐ 离散化+面积加权 ✅ 近似均匀(分辨率越高越准) ✅ 高效稳定 ⭐⭐⭐⭐⭐(推荐) 📌 结论:通过足够精细的离散化,可以在任意精度下逼近真正的二维均匀分布。 🧾 总结 要点 说明 ✅ 可行域存在 存在非空交集,可通过数学分析确认 ✅ 可实现均匀采样 不能直接独立采样,需基于面积加权 ✅ 推荐方法 离散化 $b$,按每条竖直切片的长度作为权重采样,再在 $a$ 上均匀采样 ✅ 支持扩展 可推广到任意函数约束(如 $a^2 + b^2 < 1$) Does it mean any point in regular area can be chosen in same chance, but not possible in irregular area?
最新发布
11-01
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值