凸包的判定方法:将点按逆时针排列,依次枚举三个点 a , b , c a,b,c a,b,c求向量 ( a , b ) (a,b) (a,b) ( b , c ) (b,c) (b,c),的叉乘,也就是判断 ( a , b ) (a,b) (a,b) ( b , c ) (b,c) (b,c)的夹角,如果叉乘小于0,即sin夹角大于180度,即不是凸包
注意到这里是求 ( a , b ) (a,b) (a,b) ( b , c ) (b,c) (b,c)的叉乘,而在下面的凸包求法中是求 ( a , b ) (a,b) (a,b) ( a , b ) (a,b) (a,b)的叉乘

#include <bits/stdc++.h>
using namespace std;
const int N=1e6+50;
struct Point{
   
    int x,y;
}p[N];
int n;
int cross(Point a,Point b,Point c,Point d){
   
    return (b.x-a.x)*(d.y-c.y)-(b.y-a.y)*(d.x-c.x);
}
int main(void){
   
    while(~scanf("%d",&n) && n){
   
        for(int i=0;i<n;i++){
   
            scanf("%d%d",&p[i].x,&p[i].y);
        }
        p[n]=p[0];
        p[n+1]=p[1];
        bool flag=true;
        for(int i=0;i<n;i++){
   
            if(cross(p[i],p[i+1],p[i+1],p[i+2])<0){
   
                flag=false;
                break;
            }
        }
        if(flag){
   
            printf("convex\n");
        }else{
   
            printf("concave\n");
        }
    }
    return 0;
}

凸包的求法(Graham):从初始点开始逆时针扫描,维护一个栈,每次栈顶 a a a和栈顶-1的 b b b两个点与当前点 c c c的两个向量 ( a , c ) (a,c) (a,c) ( b , c ) (b,c) (b,c),如果叉乘小于等于0,就出栈一个点,直到栈空或者栈顶两个点满足条件,这时候再把当前点 c c c加进去,最后栈中的点就是凸包上的点(逆时针)

这题是求凸包的周长,注意叉乘函数和上面的不同(两向量同起点a)

#include <bits/stdc++.h>
using namespace std;
const int N=1050;
struct Point{
   
    int x,y;
}p[N],s[N];
int top,n;
int cross(Point a,Point b,Point c){
   
    return (b.x-a.x)*(c.y-a.y)-(b.y-a.y)*(c.x-a.x);
}
double dis(Point a,Point b){
   
    return sqrt((double)(a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y));
}
bool cmp(Point a,Point b){
   
    int t=cross(p[0],a,b);
    if(t>0 || t==0 && dis(p[0],a)<dis(p[0],b)){
   
        return true;
    }else{
   
        return false;
    }
}
void init(int n){
   
    scanf("%d%d",&p[0].x,&p[0].y);
    Point p0=Point{
   p[0].x,p[0].y};
    int k=0;
    for(int i=1;i<n;i++){
   
        scanf("%d%d",&p[i].x,&p[i].y);
        if(p[i].y<p0.y || p[i].y==p0.y && p[i].x<p0.x){
   
            p0=p[i];
            k=i;
        }
    }
    p[k]=p[0];
    p[0]=p0;
    sort(p+1,p+n,cmp);
}
void graham(int n){
   
    if(n==1){
   
        top=0;
        s[0]=p[0];
    }else if(n==2){
   
        top=1;
        s[0]=p[0];
        s[1]=p[1];
    }else{
   
        top=1;
        s[0]=p[0];
        s[1]=p[1];
        for(int i=2;i<n;i++){
   
            while(top>0 && cross(s[top-1],s[top],p[i])<=0){
   
                top--;
            }
            s[++top]=p[i];
        }
    }
}
int main(void){
   
    while(~scanf("%d",&n) && n){
   
        init(n);
        graham(n);
        double ans=0;
        for(int i=1;i<=top;i++){
   
            ans+=dis(s[i],s[i-1]);
        }
        ans+=dis(s[0],s[top]);
        if(n==2){
   
            ans/=2;
        }
        printf("%.2lf\n",ans);
    }
    return 0;
}