题意
- 找凸包,建立一圈围墙,要求围墙上每个点,距离凸包上最近点大于等于l,问围墙的周长
思路
- 就是求个凸包,再加上以L为半径的圆周长,看题中图很清楚
- 貌似很多小坑点,为了节约时间的话,最好看一下discuss,基本都说清楚了~
实现
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
using namespace std;
const double eps = 1e-8;
const double PI = acos(-1.0);
int n,l;
int sgn(double x)
{
if(fabs(x) < eps)return 0;
if(x < 0)return -1;
else return 1;
}
struct Point
{
double x,y;
Point(){}
Point(double _x,double _y)
{
x = _x;y = _y;
}
Point operator -(const Point &b)const
{
return Point(x - b.x,y - b.y);
}
double operator ^(const Point &b)const
{
return x*b.y - y*b.x;
}
double operator *(const Point &b)const
{
return x*b.x + y*b.y;
}
};
double dist(Point a,Point b)
{
return sqrt((a-b)*(a-b));
}
const int MAXN = 1010;
Point list[MAXN];
int Stack[MAXN],top;
bool _cmp(Point p1,Point p2)
{
double tmp = (p1-list[0])^(p2-list[0]);
if(sgn(tmp) > 0)
return true;
else if(sgn(tmp) == 0 && sgn(dist(p1,list[0]) - dist(p2,list[0])) <= 0)
return true;
else
return false;
}
void Graham()
{
Point p0;
int k = 0;
p0 = list[0];
for(int i = 1;i < n;i++)
{
if( (p0.y > list[i].y) || (p0.y == list[i].y && p0.x > list[i].x) )
{
p0 = list[i];
k = i;
}
}
swap(list[k],list[0]);
sort(list+1,list+n,_cmp);
if(n == 1)
{
top = 1;
Stack[0] = 0;
return;
}
if(n == 2)
{
top = 2;
Stack[0] = 0;
Stack[1] = 1;
return ;
}
Stack[0] = 0;
Stack[1] = 1;
top = 2;
for(int i = 2;i < n;i++)
{
while(top > 1 && sgn((list[Stack[top-1]]-list[Stack[top-2]])^(list[i]-list[Stack[top-2]])) <= 0)
top--;
Stack[top++] = i;
}
}
int main(){
int T;
cin >> T;
while (T--){
cin>>n>>l;
for (int i=0;i<n;i++){
scanf("%lf%lf",&list[i].x,&list[i].y);
}
Graham();
double ans = l*PI*2;
for (int i=0;i<top;i++){
ans += dist(list[Stack[i]],list[Stack[(i+1)%top]]);
}
if (T != 0)
printf("%.0lf\n\n",ans);
else
printf("%.0lf\n",ans);
}
return 0;
}