首先先介绍一下叉乘
记P1=(x1,y1,z1),P2=(x2,y2,z2)
接下来进行Graham时,z1=z2=0,所以只剩下(x1*y2-x2*y1)k,当x1*y2-x2*y1>0时,即结果与k同向,所以P1在P2的右侧,=0为共线,<0为P1在P2左侧。
接下来推荐Graham讲解的博客
http://blog.csdn.net/u012328159/article/details/50808360
http://blog.csdn.net/tmljs1988/article/details/7259331
附模板:
#include<cstdio>
#include<cmath>
#include<algorithm>
using namespace std;
const int MAXN = 1005;
const double PI = acos(-1.0);
struct Point
{
int x, y;
Point(int x=0,int y=0):x(x),y(y){}
}list[MAXN];
int stack[MAXN], top, lenth, n;
void swap(int i, int j)
{
Point tmp;
tmp = list[i];
list[i] = list[j];
list[j] = tmp;
}
int cross(Point p0, Point p1, Point p2)//叉乘,以p0为起点
{
return (p1.x - p0.x)*(p2.y - p0.y) - (p1.y - p0.y)*(p2.x - p0.x);
}
double dis(Point p1, Point p2)//两点距离
{
return sqrt((double)(p2.x - p1.x)*(p2.x - p1.x) + (p2.y - p1.y)*(p2.y - p1.y));
}
bool cmp(Point p1, Point p2)//排序,极角小的在前,当极角相同时,离极坐标原点近的在前
{
int tmp = cross(list[0], p1, p2);
if (tmp>0)
return true;
else if (tmp == 0 && dis(list[0], p1)<dis(list[0], p2))
return true;
else
return false;
}
void init()
{
int k = 0;
for (int i = 1;i<n;i++)
if ((list[k].y>list[i].y) || ((list[k].y == list[i].y) && (list[k].x>list[i].x)))
k = i;//找出y最小的点作为极坐标原点,y相同找x最小
swap(0, k);//list[0]就是极坐标原点
sort(list + 1, list + n, cmp);
}
void graham()
{
if (n == 1)
{
top = 0;
stack[0] = 0;
}
else
{
for (int i = 0;i <= 1;i++)
stack[i] = i;
top = 1;
for (int i = 2;i < n;i++)
{
while (top>0 && cross(list[stack[top - 1]], list[i], list[stack[top]]) >= 0)
top--;
stack[++top] = i;
}
}
lenth = top + 1;
}
double periMeter()//凸包的周长
{
if (lenth == 1) return 0;
double res = 0;
for (int i = 0;i < lenth;i++)
res += dis(list[stack[i]], list[stack[(i + 1) % lenth]]);
return res;
}
double getArea()//凸包的面积
{
if (lenth <= 2) return 0;
double area = 0;
for (int i = 2;i < lenth;i++)//叉乘为两个向量构成的平行四边形的面积,所以最后要除以2
area += cross(list[stack[0]], list[stack[i - 1]], list[stack[i]]);
return fabs(area) / 2;
}
int main()
{
list[0] = Point(1, 0);
list[1] = Point(2, 0);
list[2] = Point(0, 1);
list[3] = Point(0, 2);
list[4] = Point(1, 1);
list[5] = Point(2, 1);
list[6] = Point(3, 1);
list[7] = Point(3, 2);
list[8] = Point(2, 3);
list[9] = Point(1, 2);
n = 10;
init();
graham();
for (int i = 0;i < lenth;++i)
printf("x:%d,y:%d\n", list[stack[i]].x, list[stack[i]].y);
printf("%f\n", periMeter());
printf("%f\n", getArea());
return 0;
}