题意
给出很多点,用线吧这些点全部包起来,求使用的最小长度,注意点和线直接有最小长度要求
题解
先按x从小到大,x相同时y从小到大排序,这样保证最左边的点和最右边的点都是必被选到的
如图,以下凸包为例,要让所有点被线包裹,那么连接AC显然是比连接AB更好的选择,当B在AC的左边时,B在AC右边时
,那么就可以以这一点设置一个单调栈储存所有满足条件的点
时三点成一线,我们选择更靠右的点。那么上凸包同理
再来处理这个距离问题,其实就只需要在每个点上画一个圆,平移直线与圆相切,由于凸边形角度加起来是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);
}