HDU_1392
这个题目比较疑惑的一点就是当N==2时,只要输出两点间距离即可,而不是输出距离的两倍。
至于为什么求凸包的周长就可以,我们不妨用反证法去证明:凸包上点绳子必然要经过的,同时我们找不到一种更优的结果使得绳子的某一部分不是在凸包的边长上。因而我们只要求得凸包并计算其周长即可。
这个算是我学习graham凸包算法之后的处女作了。
#include<stdio.h>
#include<string.h>
#include<math.h>
#include<stdlib.h>
#define MAXD 110
#define zero 1e-8
struct point
{
double x, y;
}p[MAXD], res[MAXD];
int N, P;
int dcmp(double x)
{
return fabs(x) < zero ? 0 : (x < 0 ? -1 : 1);
}
double det(double x1, double y1, double x2, double y2)
{
return x1 * y2 - x2 * y1;
}
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 ? -1 : 1;
return p->y < q->y ? -1 : 1;
}
double sqr(double x)
{
return x * x;
}
void init()
{
int i, j, k;
for(i = 0; i < N; i ++)
scanf("%lf%lf", &p[i].x, &p[i].y);
qsort(p, N, sizeof(p[0]), cmp);
}
int del(int top, int i)
{
if(dcmp(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, mint, top = 1;
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;
}
void solve()
{
int i;
double ans;
if(N == 1)
printf("0.00\n");
else if(N == 2)
printf("%.2lf\n", sqrt(sqr(p[0].x - p[1].x) + sqr(p[0].y - p[1].y)));
else
{
P = graham();
ans = 0;
for(i = 0; i < P; i ++)
ans += sqrt(sqr(res[i].x - res[i + 1].x) + sqr(res[i].y - res[i + 1].y));
printf("%.2lf\n", ans);
}
}
int main()
{
for(;;)
{
scanf("%d", &N);
if(!N)
break;
init();
solve();
}
return 0;
}