c++ 凸包 分治算法_凸包(Convex Hull)问题的三种解法: 暴力,Graham Scan,分治

#include

#include

#include

#include

#include

#include

#include

#include

#include

using namespace std;

using namespace cv;

#define e 3.3621e-4932

Point2f pmin;

bool SameSide(Point2f A, Point2f B, Point2f C, Point2f P)

{

long double k = (long double)(A.y - B.y) / (A.x - B.x);

long double b = A.y - k * A.x;

if ((C.y - k*C.x - b >= e && P.y - k*P.x - b >= e) || (C.y - k*C.x - b <= e && P.y - k*P.x - b <= e))

return true;

else

return false;

}

bool PointinTriangle1(Point2f A, Point2f B, Point2f C, Point2f P)

{

return SameSide(A, B, C, P) && SameSide(B, C, A, P) && SameSide(C, A, B, P);

}

bool cmpBy_yr(Point2f a, Point2f b)

{

return a.y < b.y;

}

bool cmpBy_yl(Point2f a, Point2f b)

{

return a.y > b.y;

}

bool cmpBy_x(Point2f a, Point2f b)

{

return a.x < b.x;

}

inline bool cmpBy_ang(const Point2f pt1, const Point2f &pt2)

{

float m1 = sqrt((float)(pt1.x * pt1.x + pt1.y * pt1.y));

float m2 = sqrt((float)(pt2.x * pt2.x + pt2.y * pt2.y));

float v1 = (pt1.x - pmin.x) * (pt2.y - pmin.y) - (pt1.y - pmin.y) * (pt2.x - pmin.x);

return (v1 > 0 || (v1 == 0 && m1 < m2));

}

void drawLine(vector points, vector p)

{

vector left, right;

int num = p.size();

int miny_index = 0, maxy_index = 0;

float k, b;

Mat Draw_Convex_Hull(600, 600, CV_8UC3, Scalar(255, 255, 255));

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

{

circle(Draw_Convex_Hull, points[i], 1, Scalar(0, 0, 0),1);

}

for (int i = 0; i < num; i++)

{

if (p[i].y < p[miny_index].y)

miny_index = i;

if (p[i].y > p[maxy_index].y)

maxy_index = i;

}

k = (p[maxy_index].y - p[miny_index].y) / (p[maxy_index].x - p[miny_index].x);

b = p[maxy_index].y - k*p[maxy_index].x;

for (int i = 0; i < num; i++)

{

if (p[i].y - k*p[i].x - b > 0)

{

left.push_back(p[i]);

}

else

{

right.push_back(p[i]);

}

}

sort(right.begin(), right.end(), cmpBy_yr);

sort(left.begin(), left.end(), cmpBy_yl);

for (int i = 0; i < right.size() - 1; i++)

{

line(Draw_Convex_Hull,right[i],right[i+1], Scalar(0, 0, 255),2);

waitKey(30);

}

for (int i = 0; i < left.size() - 1; i++)

{

line(Draw_Convex_Hull, left[i], left[i + 1], Scalar(0, 0, 255),2);

waitKey(30);

}

line(Draw_Convex_Hull, right[right.size() - 1], left[0], Scalar(0, 0, 255),2);

line(Draw_Convex_Hull, left[left.size() - 1], right[0], Scalar(0, 0, 255),2);

imshow("Convex Hull", Draw_Convex_Hull);

waitKey(0);

}

void bruteForce(vector &p, vector &vec)

{

int num = p.size();

int min_index = 0;

Point2f min = p[0], tmp;

vector flag(num,true);

for (int i = 1; i < num; i++)

{

if ((p[i].y < min.y)||(p[i].y == min.y && p[i].x < min.x))

{

min = p[i];

min_index = i;

}

}

tmp = p[0];

p[0] = min;

p[min_index] = tmp;

vec.push_back(p[0]);

for(int i = 1; i < num; i++)

for(int j = 0;j < num; j++)

for (int k = j+1; k < num; k++)

{

if (i != j&&i != k)

if (PointinTriangle1(p[j], p[k], p[0], p[i]))

flag[i] = false;

}

for (int i = 1; i < num; i++)

{

if (flag[i])

vec.push_back(p[i]);

}

}

void grahamScan(vector &p, vector &vec)

{

vector ang;

int num = p.size();

int min_index = 0;

Point2f min = p[0], tmp ,top1, top;

vector flag(num, true);

for (int i = 1; i < num; i++)

{

if ((p[i].y < min.y) || (p[i].y == min.y && p[i].x < min.x))

{

min = p[i];

min_index = i;

}

}

tmp = p[0];

p[0] = min;

pmin = min;

p[min_index] = tmp;

vec.push_back(p[0]);

sort(p.begin() + 1, p.end(), cmpBy_ang);

vec.push_back(p[1]);

vec.push_back(p[2]);

for (int i = 3; i < num; i++)

{

while (PointinTriangle1(p[i], vec[vec.size() - 2], p[0], vec[vec.size() - 1]) && vec.size() > 2)

vec.pop_back();

vec.push_back(p[i]);

}

}

void Divide_Conquer(vector &p, int l, int r, vector &vec)

{

if (r - l < 3)

return;

if (r - l == 3)

{

vec.insert(vec.end(), p.begin() + l, p.begin() + r + 1);

return;

}

double countx = 0;

for (int i = l; i <= r; i++)

countx += p[i].x;

countx /= (r - l + 1);

int k = (l + r) / 2;

vector temp_left, temp_right, answer;

Divide_Conquer(p, k + 1, r, temp_right);

Divide_Conquer(p, l, k, temp_left);

temp_left.insert(temp_left.end(), temp_right.begin(), temp_right.end());

grahamScan(p, answer);

vec.insert(vec.end(),answer.begin(),answer.end());

}

void Divide_Conquer_Warp(vector &p, vector &vec)

{

sort(p.begin(), p.end(), cmpBy_x);

Divide_Conquer(p, 0, p.size() - 1, vec);

}

int main()

{

float x, y;

int num = 100;

vector vp2f;

vector con_hull;

LARGE_INTEGER t1, t2, tc;

QueryPerformanceFrequency(&tc);

srand(time(NULL));

for (int i = 0; i < num; i++)

{

x = rand()*1. / (RAND_MAX / 500.);

y = rand()*1. / (RAND_MAX / 500.);

vp2f.push_back(Point2f(x, y));

}

//bruteForce

/* QueryPerformanceCounter(&t1); bruteForce(vp2f,con_hull); QueryPerformanceCounter(&t2); cout << "Point Numbers: " << num << "\t" << "Time of Brute Force: " << (t2.QuadPart - t1.QuadPart)*1.0 / tc.QuadPart << endl; drawLine(vp2f,con_hull);*/

// Graham Scan

QueryPerformanceCounter(&t1);

grahamScan(vp2f, con_hull);

QueryPerformanceCounter(&t2);

cout << "Point Numbers: " << num << "\t" << "Time of Graham_Scan: " << (t2.QuadPart - t1.QuadPart)*1.0 / tc.QuadPart << endl;

drawLine(vp2f, con_hull);

// Divide and Conquer

/* QueryPerformanceCounter(&t1); Divide_Conquer_Warp(vp2f, con_hull); QueryPerformanceCounter(&t2); cout << "Point Numbers: " << num << "\t" << "Time of Divide_Conquer: " << (t2.QuadPart - t1.QuadPart)*1.0 / tc.QuadPart << endl; drawLine(vp2f, con_hull); */

return 0;

}

好的,以下是Graham-Scan算法的C++实现。 ```cpp #include <bits/stdc++.h> using namespace std; struct Point { int x, y; }; // 叉积 int cross(const Point &a, const Point &b, const Point &c) { return (b.x - a.x) * (c.y - b.y) - (b.y - a.y) * (c.x - b.x); } // 求凸包,返回点集 vector<Point> convexHull(vector<Point> &points) { int n = points.size(); // 先按照x坐标从小到大排序,x坐标相同按y坐标从小到大排序 sort(points.begin(), points.end(), [](const Point &a, const Point &b) { return a.x == b.x ? a.y < b.y : a.x < b.x; }); // 求下凸壳 vector<Point> lower; for (int i = 0; i < n; ++i) { while (lower.size() >= 2 && cross(lower[lower.size() - 2], lower.back(), points[i]) <= 0) lower.pop_back(); lower.push_back(points[i]); } // 求上凸壳 vector<Point> upper; for (int i = n - 1; i >= 0; --i) { while (upper.size() >= 2 && cross(upper[upper.size() - 2], upper.back(), points[i]) <= 0) upper.pop_back(); upper.push_back(points[i]); } // 合并下凸壳和上凸壳 vector<Point> ans(lower); ans.insert(ans.end(), upper.begin() + 1, upper.end() - 1); return ans; } int main() { int n; cin >> n; vector<Point> points(n); for (int i = 0; i < n; ++i) cin >> points[i].x >> points[i].y; vector<Point> hull = convexHull(points); cout << "Convex Hull:" << endl; for (const Point &p : hull) cout << p.x << " " << p.y << endl; return 0; } ``` 在上述代码中: - `Point` 结构体表示一个点,包含 `x` 和 `y` 坐标; - `cross` 函数用于计算向量 $\overrightarrow{AB}$ 和 $\overrightarrow{AC}$ 的叉积,即 $(\overrightarrow{AB} \times \overrightarrow{AC})$,结果为正表示 $\overrightarrow{AB}$ 在 $\overrightarrow{AC}$ 的逆时针方向,结果为负表示 $\overrightarrow{AB}$ 在 $\overrightarrow{AC}$ 的顺时针方向,结果为 $0$ 表示 $\overrightarrow{AB}$ 与 $\overrightarrow{AC}$ 共线; - `convexHull` 函数用于求解凸包,输入为点集 `points`,输出为凸包点集; - 在函数内部,先按照 x 坐标从小到大排序,x 坐标相同按 y 坐标从小到大排序; - 接着求下凸壳,利用单调栈维护; - 再求上凸壳,同样利用单调栈维护; - 最后将下凸壳和上凸壳合并,得到最终的凸包点集。 希望能对你有所帮助。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值