今天又学了一种新算法,主要是编程求解平面集合问题
题目描述如下
这个题目用到的算法我们称之为凸包算法,有很多种,单核心思想都是从一个点出发,找到以出发点开始最左或者最右的一条边。
利用的是向量的叉乘的大小找到下一个点的位置
/*关键思想:利用向量的叉乘来判断点的位置*/
int cross(vector<int> &p, vector<int> &q, vector<int> &r){
return (q[0]-p[0])*(r[1]-q[1]) - (r[0]-q[0])*(q[1]-p[1]);
}
然后以找到的点为出发点,继续找下一个点,直到最后找到的点是出发点的时候,说明已经围完了
全部代码如下
class Solution {
public:
/*关键思想:利用向量的叉乘来判断点的位置*/
int cross(vector<int> &p, vector<int> &q, vector<int> &r){
return (q[0]-p[0])*(r[1]-q[1]) - (r[0]-q[0])*(q[1]-p[1]);
}
vector<vector<int>> outerTrees(vector<vector<int>>& trees) {
int n = trees.size();
//找出最下面的点,以最下面的点为出发点
int bot = 0;
for(int i = 0; i<n;i++){
if(trees[i][1] < trees[bot][1]){
bot = i;
}
}
vector<vector<int>> res;
vector<int> visit(n, 0);
int p = bot;
do{
int q = (p+1)%n;
for(int i=0; i<n; i++){
if(i!=p && cross(trees[p], trees[q], trees[i])<0){
q = i;
}
}
visit[q] = 1;
res.push_back(trees[q]);
//找出在这条边上的其他点
for(int i = 0; i<n; i++){
if(i==p){
continue;
}
if(!visit[i] && cross(trees[p], trees[q], trees[i]) == 0){
visit[i] = 1;
res.push_back(trees[i]);
/*如果i到p点的距离大于q到p点的距离的话,将i更新为q*/
int r1 = (trees[q][0]-trees[p][0])*(trees[q][0]-trees[p][0])+(trees[q][1]-trees[p][1])*(trees[q][1]-trees[p][1]);
int r2 = (trees[i][0]-trees[p][0])*(trees[i][0]-trees[p][0])+(trees[i][1]-trees[p][1])*(trees[i][1]-trees[p][1]);
if(r1<r2){
q = i;
}
}
}
p = q;
}while(p!=bot);
return res;
}
};
这个算法是最简单的凸包算法,当然还可以在进行优化,今天就先做到这吧,明天再看看优化的凸包算法
收获还是蛮大的。