tzoj 1471: Wall(凸包模板)

题意

给出很多点,用线吧这些点全部包起来,求使用的最小长度,注意点和线直接有最小长度要求

题解

先按x从小到大,x相同时y从小到大排序,这样保证最左边的点和最右边的点都是必被选到的

 如图,以下凸包为例,要让所有点被线包裹,那么连接AC显然是比连接AB更好的选择,当B在AC的左边时\overrightarrow{AC}\times\overrightarrow{AB}>0,B在AC右边时\overrightarrow{AC}\times\overrightarrow{AB}<0,那么就可以以这一点设置一个单调栈储存所有满足条件的点\overrightarrow{AC}\times\overrightarrow{AB}=0时三点成一线,我们选择更靠右的点。那么上凸包同理

再来处理这个距离问题,其实就只需要在每个点上画一个圆,平移直线与圆相切,由于凸边形角度加起来是360°,所以只需要加一个圆的周长即可

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
typedef pair<double,double> PDD;
typedef unsigned long long ULL;
mt19937 rnd(random_device{}());
uniform_int_distribution<int> dist(0,INT_MAX);   

int n,l;
PDD p[1010];
double pai = 3.1415926;

bool cmp(PDD x,PDD y)
{
    if(x.first!=y.first) return x.first<y.first;
    return x.second<y.second; 
}

double cross(PDD a,PDD b,PDD c)
{
    double x1 = a.first-c.first;
    double y1 = a.second-c.second;
    double x2 = a.first-b.first;
    double y2 = a.second-b.second;
    return x1*y2-x2*y1;
}

double dis(PDD a,PDD b)
{
    return sqrt((a.first-b.first)*(a.first-b.first)+(a.second-b.second)*(a.second-b.second));
}

int main()
{
    cin>>n>>l;
    for(int i=1;i<=n;i++)
        cin>>p[i].first>>p[i].second;
    sort(p+1,p+1+n);
    int stk[1010];
    double ans = 0;
    int tt = -1;
    for(int i=1;i<=n;i++)
    {
        while(tt>=1&&cross(p[stk[tt-1]],p[stk[tt]],p[i])>=0) tt--;
        stk[++tt] = i;
    }
    for(int i=0;i<=tt;i++)
        if(i!=0)ans += dis(p[stk[i-1]],p[stk[i]]);
    tt = -1;
    for(int i=n;i>=1;i--)
    {
        while(tt>=1&&cross(p[stk[tt-1]],p[stk[tt]],p[i])>=0) tt--;
        stk[++tt] = i;
    }
    for(int i=0;i<=tt;i++)
        if(i!=0)ans += dis(p[stk[i-1]],p[stk[i]]);
    ans += pai*2*l;
    printf("%.0lf",ans);
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值