题目:
题意:
给出一个多边形,要在外围距离r围一圈围墙,求围墙的最小长度
题解:
这个多边形肯定是个凸包啊,但是这个外围距离?!看个图冷静一下,图引自这位up
所以所求长度如图所示为凸包周长加以l为半径的圆的周长。因为绕周长一周所以为一个正圆
这里给出凸包求法:
凸包为把给定点包在内部,面积最小的凸多边形
常用Graham扫描法
- 将点按x坐标第一关键字,y坐标第二关键字排序
- 首先将p1,p2压入栈中
- 判断下一个点和栈中最后一个点组成的向量是否在当前前进方向的左边(求下凸壳),如果是的话就入栈,否则弹栈
这样求出了下凸壳,再倒着做一遍就求出来了正凸壳,合起来就是完整的凸包
通过判断叉积是否=0可以控制是否有三点共线的情况
最终栈中的点就是凸包中的点
注意输入不能有重复的点!
还有就是坐标不能只按照x或y坐标排序,否则处理不了所有点都在一条直线上的情况
时间复杂度O(nlogn)
一定要注意这里的边是top条,而不是top-1条
代码:
#include <algorithm>
#include <cstdio>
#include <cmath>
using namespace std;
const double eps=1e-9;
const double pi=acos(-1.0);
struct po
{
double x,y;
po(double X=0,double Y=0){x=X;y=Y;}
}dian[1005],stack[1005];
int dcmp(double x)
{
if (x<=eps && x>=-eps) return 0;
return (x>0)?1:-1;
}
int top=0,n;
double cj(po x,po y){return x.x*y.y-x.y*y.x;}
po operator -(po x,po y){return po(x.x-y.x,x.y-y.y);}
bool operator <(const po &a,const po &b){return a.x<b.x||(a.x==b.x && a.y<b.y);}
int sswr(double r)//四舍五入函数
{
return (r>0.0)?floor(r+0.5):ceil(r-0.5);
}
double len(po x,po y){return sqrt((x.x-y.x)*(x.x-y.x)+(x.y-y.y)*(x.y-y.y));}
void tb()
{
sort(dian+1,dian+n+1);
for (int i=1;i<=n;i++)
{
while (top>1 && dcmp(cj(stack[top]-stack[top-1],dian[i]-stack[top-1]))<=0)
top--;
stack[++top]=dian[i];
}
int k=top;
for (int i=n-1;i>=1;i--)
{
while (top>k && dcmp(cj(stack[top]-stack[top-1],dian[i]-stack[top-1]))<=0) top--;
stack[++top]=dian[i];
}
if (n>1) top--;
}
int main()
{
double l,x,y;
scanf("%d%lf",&n,&l);
for (int i=1;i<=n;i++)
{
scanf("%lf%lf",&x,&y);
dian[i]=po(x,y);
}
tb();double ans=0;
for (int i=1;i<=top;i++) ans+=len(stack[i],stack[i%top+1]);
ans+=2.0*pi*l;
printf("%d",sswr(ans));
}