Andrew算法是Graham算法的变种。
其主要思想为把凸包上的点依次放入栈中,
如果发现形成了凹多边形(叉积为负值)
就删除一些点,使得又能够维持凸的形态。
这时就会发现,处理各个点需要按照x从左往右的顺序,排序即可
当然,这只是处理了下凸的一个凸壳,倒过来再刷一次,就得到了整个凸包
代码:
#include <iostream>
#include <cmath>
#include <cstdio>
#include <algorithm>
#include <fstream>
#include <string>
#include <sstream>
using namespace std;
struct point {
int x,y;
}pt[1005];
int sta[1005], ans[1005], cnt;
int cmp(point a, point b)
{
//左下角优先,先左后下
return a.x < b.x || (a.x == b.x && a.y < b.y);
}
int cross(point p0, point p1, point p2)
{
//大于0,逆时针方向
return (p1.x-p0.x)*(p2.y-p0.y)-(p1.y-p0.y)*(p2.x-p0.x);
}
//Andrew算法
void convex(int n)
{
sort(pt, pt+n, cmp);
cnt = 0;
int top = 0;
sta[top++] = 0; //先处理 下凸包
sta[top++] = 1;
for(int i = 2; i < n; ++i)
{
while(top > 1 && cross(pt[sta[top-2]], pt[sta[top-1]], pt[i]) <= 0)
{
top--;
}
sta[top++] = i;
}
for(int i = 0; i < top; ++i)
{
ans[cnt++] = sta[i];
}
top = 0; //求上凸包,并将pt[n-1]与pt[0]连接起来
sta[top++] = n - 1;
sta[top++] = n - 2;
for(int i = n - 3; i >= 0; --i)
{
while(top > 1 && cross(pt[sta[top-2]], pt[sta[top-1]], pt[i]) <= 0)
{
top--;
}
sta[top++] = i;
}
for(int i = 0; i < top; ++i)
{
ans[cnt++] = sta[i]; //两个凸包的头结点和尾结点存入两次
}
}
int main()
{
ifstream in("points.txt");
if(in)
{
string line;
string data1;
string data2;
stringstream input;
int num = 0;
int sz;
bool first = true;
while(getline(in, line))
{
if(first)
{
sz = stoi(line);
// cout << "sz = " << sz << endl;
first = false;
} else {
input.clear();
input.str(line);
input >> data1 >> data2;
// cout << "data1 = " << data1 << endl;
pt[num].x = stoi(data1);
pt[num].y = stoi(data2);
++num;
}
}
//cout << "num = " << num << endl; // num == 9
//计算9个点组成的凸包
convex(9);
//输出凸包点的坐标
for(int i = 0; i < cnt; ++i)
{
cout << "x = " << pt[ans[i]].x << " y = " << pt[ans[i]].y << endl;
}
} else {
cout << "no such file" << endl;
}
return 0;
}
/************points.txt*******************
9
1 3
2 7
3 1
4 5
5 4
6 9
7 8
8 2
9 6
******************************************/