HDU2108(叉积判断凸多边形,凹多边形)

按照逆时针顺序,输入n个点,判断给出的图形是凸多边形,还是凹多边形。

a x b = | a | * | b | * sin (ab)


叉积的应用,观察两种多边形的特点可以看出,凹多边形因为有一部分凹进去,所以,相邻边的叉积会小于0,因为角度大于180度(图中顶点A)。

所以根据输入顺序,遍历一遍,每次求出叉积判断一下就好了。

注意是一个多边形,封闭区域,因此要遍历一圈。

#include<iostream>
#include<cstdio>
#include<cmath>
#include <algorithm>
#include<vector>
using  namespace std;
const double eps = 1e-10;

int dcmp(double x){
    if(fabs(x) < eps) return 0;
    return x < 0 ? -1:1;
}
struct Point{
    double x,y;
    Point(double x = 0,double y = 0):x(x),y(y){}

    bool operator <(const Point& b)const{
        return x < b.x || (x == b.x && y < b.y);
    }
    bool operator == (const Point &b)const {
        return dcmp(x - b.x) == 0&& dcmp(y - b.y) == 0;
    }

};
typedef Point Vector  ;
// 求向量 (x,y)的极角,atan2(y,x); -- C标准库
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){

}
*/

double Dot(Point A,Point B) {return A.x*B.x+A.y*B.y;}  //点积
double Cross(Point A,Point B) {return A.x*B.y-A.y*B.x;} //叉积
double Length(Vector A){  return sqrt(Dot(A,A));} //求向量长度
double Angle(Vector A,Vector B){ return acos(Dot(A,B) / Length(A) / Length(B)); } //求出cos ,再用acos求出角度、

double Area2(Point A,Point B,Point C){ return Cross(B-A,C-A);}
//向量旋转 公式 x' = x * cosa - y * sina, y' = x * sina + y * cosa;
Vector Rotate(Vector A,double rad){ return Vector(A.x * cos(rad) - A.y*sin(rad), A.x*sin(rad) + A.y * cos(rad));}
//计算向量的 单位 法线。
Vector Normal(Vector A){double L = Length(A); return Vector(-A.y / L , A.x /L); }
//计算交点, 调用前确保 Cross(v,w) 非0
//设 直线分别为 P + tv 和 Q + tw;
Point GetLineIntersection(Point P,Vector v,Point Q,Vector w){
    Vector u = P-Q;
    double t = Cross( w , u) / Cross( v , w );
    return P + v * t;
}
//点到直线距离
double DistanceToLine(Point P, Point A,Point B){ //叉积 除以 底
    Vector v1 = B - A, v2 = P - A;
    return fabs(Cross(v1,v2)) / Length(v1); //不取绝对值,则为有向距离
}
//点到线段的距离
double DistanceToSegment(Point P, Point A, Point B){
    if(A == B) return Length(P - A) ; // AB重合,成点对点长度
    Vector v1 = B - A, v2 = P - A, v3 = P - B;
    if(dcmp(Dot(v1,v2)) < 0) return Length(v2); // == 0 的时候是垂直的,小于零在二三象限; 即离A近;
    else if(dcmp(Dot(v1,v2)) > 0) return Length(v3);  //大于零 一四象限。
    else return fabs(Cross(v1,v2)) / Length(v1); // 垂直的情况,直接用叉积来求了。
}
Point GetLineProjection(Point P,Point A,Point B){ //获得P在线段AB上投影的节点。
    // AB向量  A + tv , Q 即投影点 A + t0v ,
    // PQ 垂直于AB ,Dot()应该为0. 所以 Dot(v , P - (A + t0v))'
    // 分配率  Dot(v , P - A) - t0 * Dot(v,v) = 0;
    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) ;
    double 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 ;
}


Point getD(Point A, Point B, Point C){ // A B C 逆时针给出
    Vector v1 = C - B;
    double a1 = Angle(A - B , v1);
    v1 = Rotate(v1, a1 / 3);

    Vector v2 = B - C;
    double a2 = Angle(A-C,v2);
    v2 = Rotate(v2 , -a2 / 3);

    return  GetLineIntersection(B,v1,C,v2);
}

Point read_Point(){
    Point tmp;
     scanf("%lf%lf",&tmp.x,&tmp.y);
     return tmp;
}
vector<Point> G;
int main(){
    int n;Point po[1010];
    while(scanf("%d",&n)!=EOF && n){
        for(int i=0;i<n;i++){
        po[i] = read_Point();
        }
        int i;
        po[n] = po[0]; po[n+1] = po[1]; //将开始两个节点放到后面,方便循环遍历。
        for(i=1;i<n+1;i++){
            double tmp = Cross(po[i] - po[i-1],po[i+1] - po[i]);
            if(tmp < 0) break;
        }
        if(i == n+1 && n >2 ){
            printf("convex\n");
        }
        else
            printf("concave\n");
    }


    return 0 ;
}



  • 2
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值