题意:输入n和l,接着顺时针输入n个点。由n个点组成一个多边形,表示一座城堡。现在需要建设城墙,城墙至少需要距离城堡l远,问城墙最少需要建设多少长。
题解:
从题目中我们知道多边形可以使一个凹的,但是我们发现,在凹的地方直接作直线的城墙比弯曲的建更短(两点之间直线最短嘛)。最后排除点凹的地方后我们发现,剩余的图形就是一个凸多边形。我们用凸包模板求得边界,然后再求城墙。
在求城墙的时候,我们发现只有拐弯点是弧度的,其余的地方等于凸包的边长。而对于m点凸包,我们令总长弧度为x,那么根据多边形内角之和,以及拐角作垂线,我们可以得到方程x+(m-2)*180+m*90*2=m*360=>x=360,正好是一个圆的周长
那么结果ans=凸包的周长+2*pi*l;然后用(int)(ans+0.5)四舍五入即可。
代码:
#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <map>
#include <set>
#include <queue>
using namespace std;
//基础点和向量运算
struct Point{
int x,y;
Point(int x=0,int y=0):x(x),y(y){}
};
typedef Point Vector;
Vector operator + (Vector A,Vector B){return Vector(A.x+B.x,A.y+B.y);}
Vector operator - (Vector A,Vector B){return Vector(A.x-B.x,A.y-B.y);}
Vector operator * (Vector A,double p){return Vector(A.x*p,A.y*p);}
Vector operator / (Vector A,double p){return Vector(A.x/p,A.y/p);}
bool operator <(const Point& a, const Point& b)
{
return a.x<b.x||(a.x==b.x&&a.y<b.y);
}
int Cross(Vector A,Vector B){return A.x*B.y-A.y*B.x;}//叉积
const int maxn=1e3+10;
const double pi=atan(1.0)*4;
int n;
Point p[maxn],ch[maxn];
int ConvexHull()//求凸包
{
sort(p,p+n);
int i,m=0,k;
for(i=0;i<n;i++)
{
while(m>1&&Cross(ch[m-1]-ch[m-2],p[i]-ch[m-2])<=0)m--;
ch[m++]=p[i];
}
k=m;
for(i=n-2;i>=0;i--)
{
while(m>k&&Cross(ch[m-1]-ch[m-2],p[i]-ch[m-2])<=0)m--;
ch[m++]=p[i];
}
if(n>1)m--;
return m;
}
double dis(Point a,Point b)//求两点距离
{
return sqrt(1.0*(a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y));
}
int main()
{
int l;
while(scanf("%d%d",&n,&l)!=EOF)
{
int i,j,k,m;
for(i=0;i<n;i++)
scanf("%d%d",&p[i].x,&p[i].y);
m=ConvexHull();
double ans=0;
for(i=1;i<m;i++)
ans+=dis(ch[i],ch[i-1]);
ans+=dis(ch[0],ch[m-1]);
ans+=2.0*pi*l;
printf("%d\n",int(ans+0.5));
}
return 0;
}