找出任何相邻子向量的最大和

本文探讨了一种算法,用于在给定数组中找出任意相邻子向量的最大和。通过实现并逐步分析代码,读者可以深入了解算法的巧妙之处。

编程珠玑上的题:

/* * 找出任何相邻子向量的最大和 * xtfggef 2012/5/7 */ #include<stdio.h> int max(int a,int b) { return (a>b)?a:b; } void main() { int a[10] = {31,-41,59,26,-53,58,97,-93,-23,84}; int maxsofar = 0; int maxendinghere = 0; for(int i=0; i<10; i++) { //遇到负数,直接赋0,相当于跳过 //遇到大一点的数,从该数开始 maxendinghere=max(maxendinghere+a[i],0); maxsofar=max(maxsofar,maxendinghere); } printf("%d\n",maxsofar); }


仔细研究了下,好精妙的算法啊!建议读者走一遍程序,观察变化,体会细节!

<think> 根据提供的引用资料,判断多边形顶点的凹凸性主要有两种方法:向量叉积法和角度和判断法。其中向量叉积法更为常用和高效。下面我将详细解释这两种方法,并说明如何找出多边形的凹顶点和凸顶点。 ## 方法1:向量叉积法(推荐) **原理**:通过计算相邻两条边的叉积来判断顶点的凹凸性。对于凸多边形,所有顶点的转向(顺时针或逆时针)应保持一致;而凹多边形至少存在一个顶点的转向与其他顶点相反。 **步骤**: 1. 按顺序遍历多边形的每个顶点 $P_i$($i$ 从0开始)。 2. 对于每个顶点 $P_i$,计算两个向量: - $\overrightarrow{v1} = P_{i-1} - P_i$(前一条边) - $\overrightarrow{v2} = P_{i+1} - P_i$(后一条边) - 注意:对于首尾顶点需要循环处理(即 $P_{-1}$ 取最后一个顶点,$P_{n}$ 取第一个顶点)。 3. 计算叉积:$r = \overrightarrow{v1} \times \overrightarrow{v2} = v1.x \cdot v2.y - v1.y \cdot v2.x$ 4. 判断凹凸性: - 若 $r > 0$:该顶点为凸顶点(假设多边形顶点按逆时针排列) - 若 $r < 0$:该顶点为凹顶点 - 若 $r = 0$:三点共线(可视为凸顶点) > **注意**:叉积符号与多边形顶点顺序有关。若顶点按顺时针排列,则符号判断相反。通常约定:逆时针排列的多边形,叉积为正表示凸顶点。 **代码实现**(参考引用[3][4]): ```cpp // 二维点结构体 struct Point { double x, y; Point(double x0 = 0, double y0 = 0) : x(x0), y(y0) {} }; // 判断顶点凹凸性(假设多边形顶点按逆时针排列) vector<bool> checkConvexVertices(vector<Point> polygon) { int n = polygon.size(); vector<bool> is_convex(n, false); for (int i = 0; i < n; i++) { // 获取前后相邻顶点索引(处理首尾循环) int prev = (i - 1 + n) % n; int next = (i + 1) % n; // 计算两个向量:v1 (Pi-1 -> Pi), v2 (Pi -> Pi+1) Point v1 = Point(polygon[prev].x - polygon[i].x, polygon[prev].y - polygon[i].y); Point v2 = Point(polygon[next].x - polygon[i].x, polygon[next].y - polygon[i].y); // 计算叉积 double cross = v1.x * v2.y - v1.y * v2.x; // 叉积 >0 时为凸顶点(逆时针) if (cross > 0) { is_convex[i] = true; // 凸顶点 } // 叉积 <0 时为凹顶点 else if (cross < 0) { is_convex[i] = false; // 凹顶点 } // 叉积=0时三点共线,可根据需求处理(通常视为凸) else { is_convex[i] = true; } } return is_convex; } ``` ## 方法2:角度和判断法 **原理**:凸多边形的内角和为 $(n-2)\times180^\circ$,而凹多边形的内角和小于该值。通过计算每个顶点处内角的角度和来判断凹凸性。该方法计算量较大(涉及反三角函数),且精度受浮点误差影响较大。 **步骤**: 1. 计算理论内角和:$total\_angle = (n-2) \times 180$(单位:度) 2. 遍历每个顶点,计算其内角: - 使用向量点积求夹角:$\theta = \cos^{-1}\left(\frac{\overrightarrow{v1} \cdot \overrightarrow{v2}}{|\overrightarrow{v1}| \cdot |\overrightarrow{v2}|}\right)$ 3. 累加所有内角角度 4. 若总和 $sum\_angle < total\_angle$,则多边形为凹多边形(但此方法只能判断整体凹凸性,**无法精确定位凹顶点**) > **注意**:此方法不推荐用于判断单个顶点凹凸性,因为内角计算无法区分局部凹凸(一个凹多边形可能所有内角和仍满足凸多边形条件)。 ## 结论 - **推荐使用向量叉积法**:高效且能精确定位每个顶点的凹凸性。 - 凹顶点判定条件(逆时针多边形):相邻边叉积为负。 - 凹顶点即“凹陷进去”的顶点,在多边形内部表现为内角大于 $180^\circ$。 通过遍历所有顶点并应用叉积判断,即可标记出所有凹顶点和凸顶点[^3][^4]。 §§相关问题§§ 1. 如何验证多边形顶点排列方向(顺时针/逆时针)? 2. 存在共线顶点时如何处理凹凸性判断? 3. 三维空间中如何判断多面体的凹凸性? </think> ### 如何找出多边形的凹顶点和凸顶点 判断多边形顶点凹凸性的核心方法是**向量叉积法**(最常用且高效),次要方法包括角度和法(计算量大)。下面详细说明两种方法: --- #### **方法1:向量叉积法(推荐)** **原理**: 通过计算顶点相邻两边的叉积方向(即向量旋转方向)判断凹凸性: - 对于顶点 $P_i$,计算向量 $\overrightarrow{v1} = P_{i-1}P_i$ 和 $\overrightarrow{v2} = P_iP_{i+1}$ - 叉积值 $r = \overrightarrow{v1} \times \overrightarrow{v2} = v1.x \cdot v2.y - v1.y \cdot v2.x$ - **判断规则**(假设多边形顶点逆时针排列): - $r > 0$ → **凸顶点**(局部左转) - $r < 0$ → **凹顶点**(局部右转) - $r = 0$ → 三点共线 **步骤**: 1. 遍历多边形每个顶点 $P_i$ 2. 计算相邻向量 $\overrightarrow{v1}$ 和 $\overrightarrow{v2}$(首尾顶点循环处理) 3. 计算叉积 $r$,根据符号标记凹凸性 **代码实现**(参考引用[3][4]): ```cpp #include <vector> using namespace std; struct Point { double x, y; }; vector<bool> findConcaveVertices(vector<Point> polygon) { int n = polygon.size(); vector<bool> isConcave(n, false); // 标记凹顶点为true for (int i = 0; i < n; i++) { // 获取相邻顶点(处理首尾循环) Point prev = polygon[(i-1+n) % n]; Point curr = polygon[i]; Point next = polygon[(i+1) % n]; // 计算向量 v1 = prev->curr, v2 = curr->next Point v1 = {prev.x - curr.x, prev.y - curr.y}; Point v2 = {next.x - curr.x, next.y - curr.y}; // 计算叉积 double cross = v1.x * v2.y - v1.y * v2.x; // 叉积 <0 时为凹顶点(逆时针多边形) if (cross < 0) { isConcave[i] = true; } } return isConcave; } ``` **输出说明**: 返回布尔数组,`isConcave[i]=true` 表示第 $i$ 个顶点是凹顶点。 --- #### **方法2:角度和法(辅助验证)** **原理**(参考引用[1]): - 凸多边形内角和恒为 $(n-2) \times 180^\circ$ - 凹多边形内角和 **小于** $(n-2) \times 180^\circ$ - 通过计算每个顶点内角判断: - 内角 $< 180^\circ$ → 凸顶点 - 内角 $> 180^\circ$ → 凹顶点 **实现要点**: 1. 用向量点积求夹角: $$\theta = \cos^{-1}\left( \frac{\overrightarrow{v1} \cdot \overrightarrow{v2}}{|\overrightarrow{v1}| \cdot |\overrightarrow{v2}|} \right)$$ 2. 累加所有内角,若总和 $< (n-2) \times 180^\circ$ 则存在凹顶点 > ⚠️ 注意:此方法计算量大且需处理浮点误差,通常作为叉积法的补充验证。 --- ### **关键事项** 1. **顶点顺序假设**: - 叉积法需固定顶点顺序(通常假设逆时针排列)。 - 若顺序未知,先用[鞋带公式](https://en.wikipedia.org/wiki/Shoelace_formula)确认方向: $$\text{面积} = \frac{1}{2}\left|\sum_{i=1}^{n} (x_i y_{i+1} - x_{i+1} y_i)\right|$$ 结果为正 → 逆时针;为负 → 顺时针(需反转叉积符号判断)。 2. **边界处理**: - 首尾顶点需循环连接(索引取模 `% n`) - 共线顶点($r=0$)可视为凸顶点 3. **复杂度**:$O(n)$,$n$ 为顶点数。 --- ### 示例分析 ![](https://via.placeholder.com/300x200?text=凸凹顶点示意图) *图中 $P_2$ 和 $P_4$ 为凹顶点(叉积 $r<0$)* 1. 计算 $P_2$ 处叉积: $\overrightarrow{v1} = P_1P_2,\ \overrightarrow{v2} = P_2P_3 → r<0$ 2. 计算 $P_4$ 处叉积: $\overrightarrow{v1} = P_3P_4,\ \overrightarrow{v2} = P_4P_5 → r<0$ ---
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值