POJ_1113

    我们可以先将问题做一个转化:先求出城堡各点的凸包,然后求距凸包的距离为L的闭合图形的周长。

    至于为什么先转化成凸包,我们不妨用反证法,如果围墙向凸包内部的方向延伸的话必然还要延伸出来,这样就会更费料。

    围墙的形状不难想象,一部分是和边平行且等于各边的边长的,还有一部分就是墙角位置的弧形,而且这个弧形的圆心角正是两条边的方向向量的夹角。

    在计算周长的时候,一部分就是凸包的周长,另一部分就是这些弧的长度之和。我们当然可以求出每个角上的弧,然后累加到一起,但这样会涉及很多的三角函数和开方函数的运算,就会有更多精度上的损失,其实细想一下会发现把这些弧拼起来就是一个完整的圆,因此算完凸包的周长之后再加上一个半径为L的圆的周长即可。

#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<math.h>
#define MAXD 1010
struct point
{
int x, y;
}p[MAXD], res[MAXD];
int N, L, P;
int cmp(const void *_p, const void *_q)
{
point *p = (point *)_p, *q = (point *)_q;
if(p->y == q->y)
return p->x - q->x;
return p->y - q->y;
}
int det(int x1, int y1, int x2, int y2)
{
return x1 * y2 - x2 * y1;
}
void init()
{
int i, j, k;
for(i = 0; i < N; i ++)
scanf("%d%d", &p[i].x, &p[i].y);
qsort(p, N, sizeof(p[0]), cmp);
}
int del(int top, int i)
{
if(det(res[top].x - res[top - 1].x, res[top].y - res[top - 1].y, p[i].x - res[top].x, p[i].y - res[top].y) < 0)
return 1;
return 0;
}
int graham()
{
int i, j, k, top = 1, mint;
res[0] = p[0], res[1] = p[1];
for(i = 2; i < N; i ++)
{
while(top && del(top, i))
-- top;
res[++ top] = p[i];
}
mint = top;
res[++ top] = p[N - 2];
for(i = N - 3; i >= 0; i --)
{
while(top != mint && del(top, i))
-- top;
res[++ top] = p[i];
}
return top;
}
double sqr(double x)
{
return x * x;
}
double calculate()
{
int i, j, k;
double ans = 0;
res[P + 1] = res[1];
for(i = 0; i < P; i ++)
ans += sqrt(sqr(res[i].x - res[i + 1].x) + sqr(res[i].y - res[i + 1].y));
return ans + 2 * acos(-1.0) * L;
}
void solve()
{
int i, j, k;
double ans;
P = graham();
ans = calculate();
printf("%.0lf\n", ans);
}
int main()
{
while(scanf("%d%d", &N, &L) == 2)
{
init();
solve();
}
return 0;
}


posted on 2012-02-17 18:14  Staginner  阅读(350)  评论(0编辑  收藏  举报