ACWING1401. 围住奶牛

ACWING1401. 围住奶牛

原题链接

描述

农夫约翰想要建造一个围栏来围住奶牛。

构建这个围栏时,必须将若干个奶牛们喜爱的地点都包含在围栏内。

现在给定这些地点的具体坐标,请你求出将这些地点都包含在内的围栏的最短长度是多少。

注意:围栏边上的点也算处于围栏内部。

思路

凸包模板题。

代码

#include <bits/stdc++.h>
using namespace std;
#define x first
#define y second
typedef pair<double,double> pdd;
int n;
const int N=10010;
pdd q[N];
int stk[N];
bool used[N];
const double EPS=1e-8;
double get_dist(pdd a,pdd b){
    double dx=a.x-b.x;
    double dy=a.y-b.y;
    return sqrt(dx*dx+dy*dy);
}
pdd operator-(pdd a,pdd b){
    return {a.x-b.x,a.y-b.y};
}
double cross(pdd a,pdd b){
    return a.x*b.y - a.y*b.x;
}
double area(pdd a,pdd b,pdd c){
    return cross(b-a,c-a);
}
int sign(double x){
    if(fabs(x)<EPS) return 0;
    if(x<0) return -1;
    return 1;
}
double andrew(){
    sort(q,q+n);
    int top=0;
    for(int i=0;i<n;i++){
        while(top>=2 && sign(area(q[stk[top-1]],q[stk[top]],q[i]))<=0){
            if(sign(area(q[stk[top-1]],q[stk[top]],q[i]))<0)
                used[stk[top--]]=false; 
            else top--;
        }
            
        stk[++top]=i;
        used[i]=true;
    }
    used[0]=false;
    for(int i=n-1;i>=0;i--){
        if(used[i]) continue;
        while(top>=2 && sign(area(q[stk[top-1]],q[stk[top]],q[i]))<=0)
            top--;
        stk[++top]=i;
    }
    double res=0;
    for(int i=2;i<=top;i++){
        res+=get_dist(q[stk[i-1]],q[stk[i]]);
    }
    return res;
}
int main(){
    scanf("%d",&n);
    for(int i=0;i<n;i++) scanf("%lf%lf",&q[i].x,&q[i].y);
    double res=andrew();
    printf("%.2f\n",res);
    return 0;
}
posted @ 2021-02-15 11:33  ans20xx  阅读(34)  评论(0编辑  收藏  举报