首页 > 代码库 > geometry1113
geometry1113
设矢量P = ( x1, y1 ),Q = ( x2, y2 ),则矢量叉积定义为由(0,0)、p1、p2和p1+p2所组成的平行四边形的带符号的面积,即:P×Q = x1*y2 - x2*y1,其结果是一个伪矢量。
叉积的一个非常重要性质是可以通过它的符号判断两矢量相互之间的顺逆时针关系:
若 P × Q > 0 , 则P在Q的顺时针方向。
若 P × Q < 0 , 则P在Q的逆时针方向。
若 P × Q = 0 , 则P与Q共线,但可能同向也可能反向。
叉积的方向与进行叉积的两个向量都垂直,所以叉积向量即为这两个向量构成平面的法向量。
如果向量叉积为零向量,那么这两个向量是平行关系。
因为向量叉积是这两个向量平面的法向量,如果两个向量平行无法形成一个平面,其对应也没有平面法向量。所以,两个向量平行时,其向量叉积为零。
#include <iostream>
#include <cmath>
using namespace std;
/*
PointSet[]:输入的点集
ch[]:输出的凸包上的点集,按照逆时针方向排列
n:PointSet中的点的数目
len:输出的凸包上的点的个数
*/
struct Point
{
float x,y;
};
//小于0,说明向量p0p1的极角大于p0p2的极角
float multiply(Point p1,Point p2,Point p0)
{
return((p1.x-p0.x)*(p2.y-p0.y)-(p2.x-p0.x)*(p1.y-p0.y));
}
float dis(Point p1,Point p2)
{
return(sqrt((p1.x-p2.x)*(p1.x-p2.x)+(p1.y-p2.y)*(p1.y-p2.y)));
}
void Graham_scan(Point PointSet[],Point ch[],int n,int &len)
{
int i,j,k=0,top=2;
Point tmp;
//找到最下且偏左的那个点
for(i=1;i<n;i++)
if ((PointSet[i].y<PointSet[k].y)||((PointSet[i].y==PointSet[k].y)&&(PointSet[i].x<PointSet[k].x)))
k=i;
//将这个点指定为PointSet[0]
tmp=PointSet[0];
PointSet[0]=PointSet[k];
PointSet[k]=tmp;
//按极角从小到大,距离偏短进行排序
for (i=1;i<n-1;i++)
{
k=i;
//找极坐标第i小的点,初始时,假设是原始的第i点(即K),确定到第n-2个以后,第n-1自动确定
for (j=i+1;j<n;j++)
if( (multiply(PointSet[j],PointSet[k],PointSet[0])>0)
//大于0,则j的极坐标比K更小
||((multiply(PointSet[j],PointSet[k],PointSet[0])==0)
&&(dis(PointSet[0],PointSet[j])<dis(PointSet[0],PointSet[k]))) )
k=j;//k保存极角最小的那个点,或者相同距离原点最近
tmp=PointSet[i];
PointSet[i]=PointSet[k];
PointSet[k]=tmp;
}
//第三个点先入栈
ch[0]=PointSet[0];
ch[1]=PointSet[1];
ch[2]=PointSet[2];
//判断与其余所有点的关系
for (i=3;i<n;i++)
{
//不满足向左转的关系,栈顶元素出栈
while(multiply(PointSet[i],ch[top],ch[top-1])>=0)
top--;
//大于0,则以top-1为源点,i的极坐标比top更小,向右偏转,不是向左。
//同时i不递增,继续用栈中深层的点考察第i节点
//必须要大于0,等于0 都不行比如:
a序列(-1,0) (0,0) (4,0) (9,0)
则st序列重复如下操作:
(-1,1),(0,0)入队。
(4,0)入队,不左拐->(0,0)出队
角度变化等于0,那么就不能算作左转
ch[++top]=PointSet[i];
//I向左偏,那么I进队,I递增
}
len=top+1;
}
const int maxN=1010;
Point PointSet[maxN];
Point ch[maxN];
int n;
int len;
int main()
{
double ans=0;
int d;
cin>>n>>d;
for(int i=0;i<n;i++)
cin>>PointSet[i].x>>PointSet[i].y;//input the data;
Graham_scan(PointSet,ch,n,len);
for(int i=0;i<len;i++)
ans+=dis(ch[i],ch[(i+1)%len]);
// 每段长短相加,最后一段是点chi[len-1]到点chi[0]的距离
ans+=2*d*acos(-1.0); //等价于圆形周长
//城堡围墙长度最小值 = 城堡顶点坐标构成的散点集的凸包总边长 + 半径为L的圆周长
cout<<(int)(ans+0.5)<<endl; //四舍五入
return 0;
}
geometry1113