7-3 符号三角形 (10 分)(思路+详解)(2)

总结

本文从基础到高级再到实战,由浅入深,把MySQL讲的清清楚楚,明明白白,这应该是我目前为止看到过最好的有关MySQL的学习笔记了,我相信如果你把这份笔记认真看完后,无论是工作中碰到的问题还是被面试官问到的问题都能迎刃而解!

MySQL50道高频面试题整理:

本文已被CODING开源项目:【一线大厂Java面试题解析+核心总结学习笔记+最新讲解视频+实战项目源码】收录

需要这份系统化的资料的朋友,可以点击这里获取

2>:输出的 结果

vector ans;用来存每次的可行解

vector path; 用来记录一次的可行解

3>:横向单层for循环 和 纵向的递归

横向的单层for循环为 0 和 1(这里我们用0和1代表’+‘和’-’)

纵向的递归为我们的n层结构

4>:递归终止条件为path.size() == n

4.当我们求出所有的可行解,我们要对其做出处理,因为我们只是穷举了第一行的所有数据

所以我们的得补充完整个二维矩阵的样子,那么我们补充的原则是,2个同号下面都是“+”,2个异号下面都是“-”。

5.当得到一个完整的图形后我们要判断 0 和 1的个数时候相等 ,如果相等则计数,就是符合要求的

符号三角形

6:图示例

在这里插入图片描述

三:上码

===================================================================

/**

思路:1.如果我们确立的第一行的符号是什么 ,那么我们就可以基本上确定我们的符号三角形是什么

因为当第一行确定的时候,那么接下来的行就是按照同号为’+’ ,异号为’-',来填写

2.在这里我们选择的解的空间是子集树(因为我们树每次都是’-‘,要么是’-')

3.具体步骤

1>:递归函数的参数

backtacking()

2>:输出的 结果

vector<vector > ans;用来存每次的可行解

vector path; 用来记录一次的可行解

3>:横向单层for循环 和 纵向的递归

横向的单层for循环为 0 和 1(这里我们用0和1代表’+‘和’-')

纵向的递归为我们的n层结构

4>:递归终止条件为path.size() == n

4.当我们求出所有的可行解,我们要对其做出处理,因为我们只是穷举了第一行的所有数据

所以我们的得补充完整个二维矩阵的样子,那么我们补充的原则是,2个同号下面都是“+”,2个异号下面都是“-”。

5.当得到一个完整的图形后我们要判断 0 和 1的个数时候相等 ,如果相等则计数,就是符合要求的

符号三角形

**/

#include<bits/stdc++.h>

using namespace std;

vector<vector > ans;

vector path;

int N;

void backtacking(){

if (path.size() == N) {

ans.push_back(path);

return;

}

for (int i = 0; i <= 1; i++) {

path.push_back(i);

backtacking();

path.pop_back();

}

}

int main(){

int count = 0;

cin >> N;

backtacking();

for (int i = 0; i < ans.size(); i++) {

int array[N][N];//将每一次的可行解建立一个二维矩阵

memset(array, -1, sizeof(array));//初始化为-1;

for (int j = 0; j < N; j++) {

array[0][j] = ans[i][j];

}

for (int k1 = 1; k1 < N; k1++) {

for (int k2 = 0; k2 < N - k1; k2++) {// N - k1 :因为这里是逐层递减的

if (array[k1-1][k2] == array[k1-1][k2+1]) { //上一行的符号相同

array[k1][k2] = 0; //这里我们用0和1代表’+‘和’-’

}else{

array[k1][k2] = 1;

}

}

}

int cnt1 = 0;

int cnt2 = 0;

for (int k3 = 0; k3 < N; k3++) {

for (int k4 = 0; k4 < N; k4++) {

if (array[k3][k4] == 0) {

cnt1++;

}

if (array[k3][k4] == 1){

cnt2++;

}

// cout << array[k3][k4] << ’ ';

}

// cout << endl;

}

最后

笔者已经把面试题和答案整理成了面试专题文档

image

image

image

image

image

image

本文已被CODING开源项目:【一线大厂Java面试题解析+核心总结学习笔记+最新讲解视频+实战项目源码】收录

需要这份系统化的资料的朋友,可以点击这里获取

[外链图片转存中…(img-9RfpIh9Q-1715800118001)]

[外链图片转存中…(img-BHJs3Ymd-1715800118002)]

本文已被CODING开源项目:【一线大厂Java面试题解析+核心总结学习笔记+最新讲解视频+实战项目源码】收录

需要这份系统化的资料的朋友,可以点击这里获取

<think>嗯,用户问的是用C++实现治法结合三角形面积来求凸包。首先,我得回忆一下凸包的相关算法。治法通常是将问题解成小问题处理再合并,而凸包的常见治方法是类似快排的思路,按点集成左右两部别求凸包再合并。不过用户提到用三角形面积,可能是在合并的时候利用面积来判断点的位置。 首先,治法求凸包的步骤大致是:将点集排序后成左右两部,递归求解左右子集的凸包,然后合并两个凸包。合并的关键在于找到上下切线,把两个凸包连接起来。这时候可能需要计算面积来判断点是否在三角形内部或者外部。 用户提到用三角形面积,可能是在合并过程中,通过计算三个点组成的三角形面积来判断点的位置。比如,如果三个点的面积为正,说明是逆时针排列,可能作为凸包边界的一部;如果为负或零,则可能在内部或共线,需要排除。 接下来要考虑如何具体实现。治法的递归基应该是什么?当点集很小的时候,比如三个点直接构成凸包。排序的话,可能需要按照x坐标排序,这样左右子集更方便。合并时,如何找到上下切线?可能需要用类似旋转卡壳的方法,或者通过比较两个凸包的极值点。 然后,如何用三角形面积辅助合并过程?比如,在确定某一点是否属于合并后的凸包时,可能需要检查该点相对于当前边的位置。利用向量叉积(即三角形面积的两倍)来判断方向。如果叉积为正,说明该点在外侧,可能需要调整切线。 代码结构方面,可能需要定义点的结构体,包含x和y坐标。然后有递归函数,当点集数目小于等于3时直接返回凸包(注意处理共线情况)。否则,成左右两部递归求解,之后合并。合并函数需要找到两个凸包的上下切线,可能需要遍历两个凸包的顶点,利用叉积判断方向是否正确。 需要注意的点包括:点的去重,避免重复计算;处理共线点的情况;合并时如何高效地找到切线。此外,治法的时间复杂度应该是O(n log n),但实现时需要确保合并步骤的复杂度足够低。 可能遇到的困难是合并两个凸包的正确性和效率。比如,如何确保找到正确的上下切线,这可能需要多次调整左右凸包的指针,比较各点的叉积符号。利用三角形面积(叉积)的正负来判断点的位置是关键步骤。 总结思路:将点集排序后治,递归求解子凸包,合并时利用叉积判断点的位置来找到连接两个子凸包的切线,最终形成整个凸包。代码实现中需要注意递归终止条件、点的排序、合并算法的正确性以及处理特殊情况如共线点。</think>下面详细介绍如何使用治法结合三角形面积法在C++中实现凸包计算: ### 治法求凸包的核心思想 1. **解**:将点集按x坐标排序,割为左右两个子集 2. **递归**:对左右子集别求凸包 3. **合并**:合并两个子凸包,关键步骤是找到上下切线 ### 关键步骤详解 #### 1. 准备工作 ```cpp struct Point { double x, y; Point(double _x = 0, double _y = 0) : x(_x), y(_y) {} }; // 计算叉积(三角形面积的两倍) double cross(const Point& o, const Point& a, const Point& b) { return (a.x - o.x) * (b.y - o.y) - (a.y - o.y) * (b.x - o.x); } ``` #### 2. 合并步骤实现 ```cpp // 查找连接两个凸包的切线 void findTangent(vector<Point>& left, vector<Point>& right, int& a, int& b) { int n = left.size(), m = right.size(); int p = 0, q = 0; // 找左凸包最右点和右凸包最左点 for(int i=1; i<n; ++i) if(left[i].x > left[p].x) p = i; for(int i=1; i<m; ++i) if(right[i].x < right[q].x) q = i; // 上切线 while(true) { bool changed = false; while(cross(left[p], right[q], right[(q+1)%m]) < 0) q = (q+1)%m; while(cross(right[q], left[p], left[(p-1+n)%n]) > 0) { p = (p-1+n)%n; changed = true; } if(!changed) break; } a = p; b = q; } ``` #### 3. 治主函数 ```cpp vector<Point> convexHull(vector<Point>& points, int l, int r) { if(r - l <= 3) { // 递归基:直接处理小集合 vector<Point> hull; // 这里需要实现基础凸包构建(略) return hull; } int mid = (l + r)/2; vector<Point> leftHull = convexHull(points, l, mid); vector<Point> rightHull = convexHull(points, mid, r); // 合并两个凸包 int a, b; findTangent(leftHull, rightHull, a, b); // 构建合并后的凸包(需要实现连接逻辑) vector<Point> merged; // ... 连接左右凸包并过滤内部点 return merged; } ``` ### 算法特点 1. **时间复杂度**:$$O(n \log n)$$ 2. **空间复杂度**:$$O(n)$$ 3. **关键优化**:利用叉积(三角形面积)快速判断点的相对位置 ### 验证方法 ```cpp bool isConvex(const vector<Point>& hull) { int n = hull.size(); if(n < 3) return false; int sign = 0; for(int i=0; i<n; ++i) { double c = cross(hull[i], hull[(i+1)%n], hull[(i+2)%n]); if(c != 0) { if(sign == 0) sign = c > 0 ? 1 : -1; else if(sign * c < 0) return false; } } return true; } ``` ### 应用场景 - 计算机图形学中的碰撞检测 - GIS系统中的区域划 - 模式识别中的形状析 ### 注意事项 1. 输入点集需要先进行去重处理 2. 合并时要注意处理共线点的情况 3. 实际实现时需要处理各种边界条件 这种算法将治策略与几何特性巧妙结合,通过三角形面积的几何意义(叉积)高效判断点的位置关系,是计算几何中的经典应用。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值