为您读题:
T组数据,每组有n,L,和给定的n组整数数对。整数数对表示点的坐标。求:一个周长最小的几何图形,使得该图形上任何一点到原点对构成的多边形的距离都不小于L。
为您解析:
- 既然是不小于,那么我们当然取等于。
- 在一条边外距离为L的是和该边构成矩形的一条平行边
-
拐角怎么办?
- 一种想法是:我们使得拐角处图形的任何一处到该拐点的距离都是L,这构成了一个圆弧
- 多边形的拐角(即为外角和)永远是360°,所以我们在统计答案的时候加上 2 ∗ π ∗ L 2*\pi*L 2∗π∗L即可。
为你答疑:
万一是个凹多边形怎么办呢?
再如图所示
如果我们让城墙随着D点的凹陷而拐进去,会发现反而不如直接连接与圆E和圆N的城墙拐点,因为三角形两边之和大于第三边。
我们发现,直线的城墙,每条边都和城堡的边长一样啊,这不就是一个凸包吗?
于是,问题被转化成了求二维凸包的问题。
为你提示:
这道题有点抽风,UVA给定的要求是每两个答案之间空一行并且文末只有一个换行。
特判剩余组数T即可。
为你打码(大雾):
#include<bits/stdc++.h>
using namespace std;
const double pi=acos(-1);
struct point
{
double x,y;
};
point all[2000],chose[2000];
inline point operator -(const point& a,const point& b)
{return (point){a.x-b.x,a.y-b.y};}
inline double operator *(const point& a,const point& b)
{return a.x*b.y-a.y*b.x;}
inline double dis(point a,point b)
{return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y));}
bool cmp(point a,point b)
{
return (a.x==b.x)?(a.y<b.y):(a.x<b.x);
}//按照横坐标排序
int INCLUDE(int n)
{
//上下求两个凸壳
int m=1;
chose[1]=all[1];
for(int i=2;i<=n;i++)
{
while(m>1&&(all[i]-chose[m])*(chose[m]-chose[m-1])<0) m--;
chose[++m]=all[i];
}
int last=m;
for(int i=n-1;i>0;i--)
{
while(m>last&&(all[i]-chose[m])*(chose[m]-chose[m-1])<0) m--;
chose[++m]=all[i];
}
if(m>1) m--;
return m;
}
inline int read()
{
int n=0,k=1;
char c=getchar();
while(c>'9'||c<'0') {if(c=='-') k=-1; c=getchar();}
while(c<='9'&&c>='0') {n=(n<<1)+(n<<3)+(c^48); c=getchar(); }
return n*k;
}
int n,mm,T;
inline void prtans(int m)
{
double ans=0;
for(int i=1;i<=m;i++)
{
ans+=dis(chose[i],chose[i+1]);
}
ans+= 2.0*pi*mm;
if(T) printf("%.0lf\n\n",ans);
else printf("%.0lf\n",ans);
}
int main()
{
T=read();
while(T--)
{
n=read();
mm=read();
for(int i=1;i<=n;i++)
{
all[i].x=read();
all[i].y=read();
}
stable_sort(all+1,all+n+1,cmp);
int tot=INCLUDE(n);
prtans(tot);
}
return 0;
}