Fencing the Cows_usaco 5.1_凸包

针对农夫约翰希望用最少资源围住所有奶牛吃草点的问题,本文介绍了一个高效的算法解决方案。通过计算几何中的凸包算法,求得围住所有点所需的最短围栏长度。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Description


  农夫约翰想要建造一个围栏用来围住他的奶牛,可是他资金匮乏。他建造的围栏必须包括他的奶牛喜欢吃草的所有地点。对于给出的这些地点的坐标,计算最短的能够围住这些点的围栏的长度。

Input


输入数据的第一行包括一个整数 N。N(0 <= N <= 10,000)表示农夫约翰想要围住的放牧点的数目。接下来 N 行,每行由两个实数组成,Xi 和 Yi,对应平面上的放牧点坐标(-1,000,000 <= Xi,Yi <= 1,000,000)。数字用小数表示。

Output


输出必须包括一个实数,表示必须的围栏的长度。答案保留两位小数。

Analysis


裸的凸包,这么良心的题目已经很少见了

Code


/*
ID:wjp13241
PROG:fc
LANG:C++
*/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <iostream>
#include <algorithm>
#include <math.h>
#include <vector>
#include <stack>
#include <queue>
#define fo(i,a,b) for (int i=a;i<=b;i++)
#define dfo(i,a,b) for (int i=a;i>=b;i--)
#define fil(x,t) memset(x,t,sizeof(x))
#define min(x,y) x<y?x:y
#define max(x,y) x>y?x:y
#define ll long long
#define INF 0x7f7f7f7f
#define EPS 1e-4
#define L 351
#define N 10001
#define E N*N+1
using namespace std;
struct pos{
    double x,y;
    bool operator<(pos a){return a.x<x||a.x==x&&a.y<y;}
}t[N];
int s[N];
double cros(pos a,pos b,pos c){return (a.x-c.x)*(b.y-c.y)-(b.x-c.x)*(a.y-c.y);}
double dist(pos a,pos b){return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y));}
bool cmp(pos a,pos b){return ((cros(a,b,t[0])>0)||(!(cros(a,b,t[0]))&&(dist(a,t[0])<dist(b,t[0]))));}
int main()
{
    freopen("fc.in","r",stdin);
    freopen("fc.out","w",stdout);
    ios::sync_with_stdio(false);
    int n;
    scanf("%d",&n);
    {
        for (int i=0;i<n;i++)
        {
            scanf("%lf%lf",&t[i].x,&t[i].y);
            if (t[i]<t[0])
            {
                pos tmp=t[i];
                t[i]=t[0];
                t[0]=tmp;
            }
        }
        sort(t+1,t+n,cmp);
        int top=3;
        s[1]=0;
        s[2]=1;
        s[3]=2;
        for (int i=3;i<n;i++)
        {
            while (cros(t[i],t[s[top]],t[s[top-1]])>=0)
                --top;
            s[++top]=i;
        }
        double ans=dist(t[s[1]],t[s[top]]);
        if (n==1)
            ans=0;
        else
            if (n==2)
                ans=dist(t[s[1]],t[s[2]])*2;
            else
                for (int i=1;i<top;i++)
                    ans+=dist(t[s[i]],t[s[i+1]]);
        printf("%.2lf\n",ans);
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值