poj 3348 Cows 凸包模板题

来源:互联网 发布:免费cms源代码php 编辑:程序博客网 时间:2024/06/05 18:50

题意:给定n个点,求这n个点构成的凸包的面积。

题解:典型的凸包模板题。先求m个点组成的凸包,然后根据凸包上的一个点,将凸包分成m-2个三角形,面积就是m-2个三角形之和。三角形面积等于两条边的叉积/2.

凸包求法讲解:

1)先将点根据横坐标从小到大排序

2)然后需要了解叉积。根据两个向量的叉积,我们可以知道一条边是在另一条边的上方还是下方。

3)接着先求凸包的下半部分。遍历点,每新进来一个点,跟已求得的凸包边比较,用叉积Cross(ch[m-1]-ch[m-2],p[i]-ch[m-2]),判断新加点是在已成凸包的外面还是里面。若是在外面,则删除所有边,当边向量和该边的起点到新增点所称向量叉积小于0,即删除在凸包内的点;将新增点加入到凸包数组中,形成新的凸包。以此类推得到凸包下边。

具体过程如下图所示,开始P1,P2,P3,P4,P6都在凸包数组中,现在加入P7;由于P4P6在P4P7上方(用叉积判),所以删除P6;由于P3P4在P3P7上方,所以删除P4;由于P2P3在P2P7下方,所以停止删除,将P7加入到凸包数组中,得到新的凸包数组P1,P2,P3,P7。接着遍历下一个点,如此反复,直到遍历所有的点,就可以得到凸包的下半部分了。

4)跟3)同理得到凸包上边,最后得到的数组就是凸包了。



代码:

#include <cstdio>#include <cstdlib>#include <cmath>#include <cstring>#include <iostream>#include <algorithm>#include <map>#include <set>#include <queue>using namespace std;//基础点和向量运算struct Point{    double x,y;    Point(double x=0,double y=0):x(x),y(y){}};typedef Point Vector;Vector operator + (Vector A,Vector B){return Vector(A.x+B.x,A.y+B.y);}Vector operator - (Vector A,Vector B){return Vector(A.x-B.x,A.y-B.y);}Vector operator * (Vector A,double p){return Vector(A.x*p,A.y*p);}Vector operator / (Vector A,double p){return Vector(A.x/p,A.y/p);}bool operator <(const Point& a, const Point& b){    return a.x<b.x||(a.x==b.x&&a.y<b.y);}const double eps=1e-10;int dcmp(double x)//判断正负,或者等于0{    if(fabs(x)<eps)return 0;else return x<0?-1:1;}bool operator==(const Point& a,const Point &b){    return dcmp(a.x-b.x)==0&&dcmp(a.y-b.y)==0;}double Dot(Vector A, Vector B){return A.x*B.x+A.y*B.y;}//点积double Length(Vector A){return sqrt(Dot(A,A));}//OA长double Angle(Vector A,Vector B){return acos(Dot(A,B)/Length(A)/Length(B));}//OA和OB的夹角double Cross(Vector A,Vector B){return A.x*B.y-A.y*B.x;}//叉积double Area2(Point A,Point B,Point C){return Cross(B-A,C-A);}//三角形面积Vector Rotate(Vector A,double rad)//rad为弧度,旋转rad度{    return Vector(A.x*cos(rad)-A.y*sin(rad),A.x*sin(rad)+A.y*cos(rad));}Vector Normal(Vector A)//A的单位法向量,A不能为零向量{    double L=Length(A);    return Vector(-A.y/L,A.x/L);}//点和直线//P+tv表示一条直线,P为点,tv为方向向量Point GetLineIntersection(Point P,Vector v,Point Q,Vector w)//求直线交点,确保存在交点,即Cross(v,w)非0{    Vector u=P-Q;    double t=Cross(w,u)/Cross(v,w);    return P+v*t;}double DistanceToLine(Point P,Point A,Point B)//P点到直线AB的距离{    Vector v1=B-A,v2=P-A;    return fabs(Cross(v1,v2)/Length(v1));}double DistanceToSegment(Point P,Point A,Point B)//点P到线段AB的距离{    if(A==B)return Length(P-A);    Vector v1=B-A,v2=P-A,v3=P-B;    if(dcmp(Dot(v1,v2))<0)return Length(v2);    else if(dcmp(Dot(v1,v3))>0)return Length(v3);    else return fabs(Cross(v1,v2)/Length(v1));}Point GetLineProjection(Point P,Point A,Point B)//点在直线上的投影{    Vector v=B-A;    return A+v*(Dot(v,P-A)/Dot(v,v));}bool SegmentProperIntersection(Point a1,Point a2,Point b1,Point b2)//判断线段相交,不在端点相交{    double c1=Cross(a2-a1,b1-a1),c2=Cross(a2-a1,b2-a1),c3=Cross(b2-b1,a1-b1),c4=Cross(b2-b1,a2-b1);    return dcmp(c1)*dcmp(c2)<0&&dcmp(c3)*dcmp(c4)<0;}bool OnSegment(Point p,Point a1,Point a2)//判断点是否在线段上(不包括端点){    return dcmp(Cross(a1-p,a2-p))==0&&dcmp(Dot(a1-p,a2-p))<0;}//多边型double ConvexPolygonArea(Point* p,int n)//多边形面积,,点按顺序{    double area=0;    for(int i=1;i<n-1;i++)        area+=Cross(p[i]-p[0],p[i+1]-p[0]);    return area/2;}int ConvexHull(Point *p,Point *ch,int n)//求凸包{    sort(p,p+n);    int i,m=0,k;    for(i=0;i<n;i++)    {        while(m>1&&Cross(ch[m-1]-ch[m-2],p[i]-ch[m-2])<=0)m--;        ch[m++]=p[i];    }    k=m;    for(i=n-2;i>=0;i--)    {        while(m>k&&Cross(ch[m-1]-ch[m-2],p[i]-ch[m-2])<=0)m--;        ch[m++]=p[i];    }    if(n>1)m--;    return m;}const int maxn=1e4+10;Point p[maxn],ch[maxn];int n;int main(){    while(scanf("%d",&n)!=EOF)    {        int i,j,k,m;        for(i=0;i<n;i++)            scanf("%lf%lf",&p[i].x,&p[i].y);        m=ConvexHull(p,ch,n);        double ans;        ans=ConvexPolygonArea(ch,m);        printf("%d\n",(int)(ans/50.0));    }    return 0;}


0 0
原创粉丝点击