关注
#include <iostream>
#include <vector>
#include <math.h>
#include <algorithm>
using namespace std;
using std::vector;
class Solution {
public:
int chengbao(vector<vector<int>> &allPos) {
vector<vector<int>> CH = allPos;
CalcConvexHull(CH);//求凸包
show(CH,"凸包点:");//凸包点形成环,去掉环上的点会形成缺口
vector<vector<int>> innerPos = differenceSet(allPos, CH);//凸包里面的点
if(innerPos.empty()) return 0;
//show(innerPos,"差集:");
int result = 0, gapSize = 1;
while(CH.size() - gapSize >= 3){//凸包剩下4个点的时候肯定能找到解
result = testResultByFixGap(allPos, innerPos, CH, gapSize);
if(result > 0) return result;
gapSize++;
}
}
private:
void CalcConvexHull(vector<vector<int>> &vecSrc) {
if(vecSrc.size() < 3) return;
vector<int> ptBase = vecSrc.front(); //将第1个点预设为最小点
for(auto i = vecSrc.begin() + 1; i != vecSrc.end(); ++i){
//如果当前点的y值小于最小点,或y值相等,x值较小
if((*i)[1] < ptBase[1] || ((*i)[1] == ptBase[1] && (*i)[0] > ptBase[0])){
ptBase[0] = (*i)[0];//将当前点作为最小点
ptBase[1] = (*i)[1];
}
}
//cout<< "基点:"<<ptBase[0] << ptBase[1] <<endl;
//计算出各点与基点构成的向量
for(auto i = vecSrc.begin(); i != vecSrc.end();){
//排除与基点相同的点,避免后面的排序计算中出现除0错误
if((*i)[0] == ptBase[0] && (*i)[1] == ptBase[1]){
i = vecSrc.erase(i);
} else {
(*i)[0] -= ptBase[0];
(*i)[1] -= ptBase[1];
++i;
}
}
sort(vecSrc.begin(), vecSrc.end(), &CompareVector);//按各向量与横坐标之间的夹角排序
vecSrc.erase(unique(vecSrc.begin(), vecSrc.end()), vecSrc.end());//删除相同的向量
//计算得到首尾依次相联的向量
vector<int> lastVec = vecSrc.back();
for(auto i = vecSrc.rbegin(); i != vecSrc.rend() - 1; ++i ){
auto iNext = i + 1;
//向量三角形计算公式
(*i)[0] -= (*iNext)[0];
(*i)[1] -= (*iNext)[1];
}
lastVec[0] *= -1, lastVec[1] *= -1;
vecSrc.push_back(lastVec);
//依次删除不在凸包上的向量
for (auto i = vecSrc.begin() + 1; i != vecSrc.end(); ++i){
//回溯删除旋转方向相反的向量,使用外积判断旋转方向
for (auto iLast = i - 1; iLast != vecSrc.begin();){
int v1 = (*i)[0] * (*iLast)[1], v2 = (*i)[1] * (*iLast)[0];
//如果叉积小于0,则无没有逆向旋转 如果叉积等于0,还需判断方向是否相逆
if(v1 > v2 || (v1 == v2 && (*i)[0] * (*iLast)[0] > 0 && (*i)[1] * (*iLast)[1] > 0))
break;
//删除前一个向量后,需更新当前向量,与前面的向量首尾相连 向量三角形计算公式
(*i)[0] += (*iLast)[0], (*i)[1] += (*iLast)[1];
iLast = (i = vecSrc.erase(iLast)) - 1;
}
}
//将所有首尾相连的向量依次累加,换算成坐标
vecSrc.front()[0] += ptBase[0], vecSrc.front()[1] += ptBase[1];
for(auto i = vecSrc.begin() + 1; i != vecSrc.end(); ++i){
(*i)[0] += (*(i - 1))[0], (*i)[1] += (*(i - 1))[1];
}
}
// 比较向量中哪个与x轴向量(1, 0)的夹角更大
static bool CompareVector(vector<int> &pt1, vector<int> &pt2) {
float m1 = sqrt((float)(pt1[0] * pt1[0] + pt1[1] * pt1[1]));
float m2 = sqrt((float)(pt1[0] * pt1[0] + pt1[1] * pt1[1]));
float v1 = pt1[0] / m1, v2 = pt1[1] / m2;
return (v1 > v2 || v1 == v2 && m1 < m2);
}
void show(vector<vector<int>> para, string explain){
cout<< explain <<endl;
for(auto i:para){
for(auto j:i){
cout << j;
}
cout<<endl;
}
}
//求差集A-B
vector<vector<int>> differenceSet(vector<vector<int>> &setA, vector<vector<int>> &setB){
vector<vector<int>> result;
for(auto i : setA){
if(find(setB.begin(), setB.end(), i) == setB.end()){
result.push_back(i);
}
}
return result;
}
int testResultByFixGap(vector<vector<int>> &allPos, vector<vector<int>> &innerPos, vector<vector<int>> &CH, int gapSize){
for(int i = 0; i != CH.size(); i++){
vector<vector<int>> gapPos = getGapPos(CH, i, gapSize);
show(gapPos,"缺口坐标:");
for(auto curPos : innerPos){//遍历内点的凸包会更高效
int x1 = curPos[0] - gapPos[0][0], y1 = curPos[1] - gapPos[0][1],
x2 = gapPos[1][0] - curPos[0], y2 = gapPos[1][1] - curPos[1];
int v1 = x2 * y1, v2 = y2 * x1;//向量叉积判断方向
if(v1 > v2) return CH.size() - gapSize + innerPos.size();
}
}
return 0;//一个城堡也没有
}
//求两个缺口坐标 输入:原始坐标,起始位置,删除元素个数 输出:删除后两端点
vector<vector<int>> getGapPos(vector<vector<int>> &Pos, int curIndex, int num){
vector<vector<int>> result;
int lastIndex = Pos.size() - 1;
int index1, index2;//缺口点坐标索引
index1 = curIndex - 1;
if(index1 < 0) index1 = lastIndex;
index2 = curIndex + num;
if(index2 > lastIndex) index2 -= (lastIndex + 1);
result.push_back(Pos[index1]);
result.push_back(Pos[index2]);
return result;
}
};
int main()
{
using std::vector;
using std::string;
using std::cout;
Solution test;
int numPos = 5;
int allPos[numPos][2]={{0,0},{0,3},{3,0},{3,3},{1,1}};
vector<vector<int>> allPosVec;
for(int i = 0; i < numPos; i++){
vector<int> Pos;
Pos.push_back(allPos[i][0]);
Pos.push_back(allPos[i][1]);
allPosVec.push_back(Pos);
}
for(auto i:allPosVec){
for(auto j:i){
cout << j;
}
cout<<endl;
}
int res = test.chengbao(allPosVec);
cout<< "最终结果"<< res <<endl;
}
查看原帖
点赞 评论
相关推荐
点赞 评论 收藏
分享
点赞 评论 收藏
分享
牛客热帖
更多
正在热议
更多
# 你的实习产出是真实的还是包装的? #
34733次浏览 433人参与
# 牛友的志愿填报指南 #
62953次浏览 484人参与
# 厦门银行科技岗值不值得投 #
15613次浏览 359人参与
# 你的实习什么时候入职 #
366562次浏览 2355人参与
# 学历VS实习,哪个更重要? #
1584次浏览 46人参与
# 工作上你捅过哪些篓子? #
68283次浏览 315人参与
# uu们,春招你还来吗? #
62754次浏览 734人参与
# 面试紧张时你会有什么表现? #
33916次浏览 205人参与
# 面试中,你被问过哪些奇葩问题? #
96001次浏览 1259人参与
# 面试被问到不会的问题,你怎么应对? #
25420次浏览 645人参与
# 你都用vibe coding做过什么? #
21434次浏览 810人参与
# 机械人,签完三方你在忙什么? #
83887次浏览 266人参与
# 你觉得大几开始实习最合适? #
29661次浏览 308人参与
# AI Coding实战技巧 #
15163次浏览 299人参与
# 你见过哪些招聘隐形歧视? #
24364次浏览 214人参与
# 国庆前的秋招小结 #
291162次浏览 1742人参与
# 哔哩哔哩笔试 #
35067次浏览 142人参与
# 如果人生可以debug你会改哪一行? #
12736次浏览 167人参与
# 秋招特别不鸣谢 #
93185次浏览 685人参与
# 应届生被毁约被毁意向了怎么办 #
65295次浏览 313人参与
# 海康威视求职进展 #
132264次浏览 551人参与
查看5道真题和解析