http://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=CGL_4_A
安德鲁算法
安德鲁算法判断凸包需要用到叉积
关于叉积
首先在二维坐标下介绍一些定义:
点:A(x1,y1),B(x2,y2)
向量:向量AB=( x2 - x1 , y2 - y1 )= ( x , y );
向量的模 |AB| = sqrt ( x*x+y*y );
向量的点积: 结果为 x1*x2 + y1*y2。
点积的结果是一个数值。
点积的集合意义:我们以向量 a 向向量 b 做垂线,则 | a | * cos(a,b)为 a 在向量 b 上的投影,即点积是一个向量在另一个向量上的投影乘以另一个向量。且满足交换律
应用:可以根据集合意义求两向量的夹角,
cos(a,b) =( 向量a * 向量b ) / (| a | * | b |) = x1*x2 + y1*y2 / (| a | * | b |)
向量的叉积: 结果为 x1*y2-x2*y1
叉积的结果也是一个向量,是垂直于向量a,b所形成的平面,如果看成三维坐标的话是在 z 轴上,上面结果是它的模。
方向判定:右手定则,(右手半握,大拇指垂直向上,四指右向量a握向b,大拇指的方向就是叉积的方向)
叉积的集合意义:1:其结果是a和b为相邻边形成平行四边形的面积。
2:结果有正有负,有sin(a,b)可知和其夹角有关,夹角大于180°为负值。
3:叉积不满足交换律
应用:
1:通过结果的正负判断两矢量之间的顺逆时针关系
若 a x b > 0表示a在b的顺时针方向上
若 a x b < 0表示a在b的逆时针方向上
若 a x b == 0表示a在b共线,但不确定方向是否相同
在顺时针方向上为凸包
否则是凹进去的。
以此依次加点。
将坐标按照x从小到大排序。
先加上面的凸包 然后加下面的凸包。
凸包
#include <bits/stdc++.h>
using namespace std;
#define mo 100005
struct node
{
int x,y;
}d[mo],p[mo];
int chaji(node a,node b,node c)//叉积计算
{
return ((b.x-a.x)*(c.y-a.y)-(b.y-a.y)*(c.x-a.x));
}
bool cmp(node a,node b)//坐标点排序
{
if(a.y!=b.y)return a.y<b.y;
return a.x<b.x;
}
void run(int n)
{
sort(d,d+n,cmp);
int tot=0;
for(int i=0;i<n;i++)
{
while(tot>1&&chaji(p[tot-2],p[tot-1],d[i])<0) tot--;
p[tot++]=d[i];
}
for(int i=n-2;i>=0;i--)
{
while(tot>1&&chaji(p[tot-2],p[tot-1],d[i])<0) tot--;
p[tot++]=d[i];
}
cout<<tot-1<<endl;
for(int i=0;i<tot-1;i++)
{
cout<<p[i].x<<' '<<p[i].y<<endl;
}
}
int main()
{
int n;
while(cin>>n)
{
for(int i=0;i<n;i++)
cin>>d[i].x>>d[i].y;
run(n);
}
}