POJ

来源:互联网 发布:java ee和java web 编辑:程序博客网 时间:2024/05/16 04:51

点我看题

题意:给出n个点的坐标,想要在这n个点外面建一个墙,要求每个点到墙的距离得大于等于l,求墙的最小周长。

分析:就是求凸包的长加上一个圆的周长,自行YY~嘻嘻嘻,用graham扫描法求解。

参考代码:

#include<cstdio>#include<cmath>#include<cstring>#include<algorithm>#include<iostream>using namespace std;const double PI = acos(-1.0);const int maxn = 1e3+10;int n,l;struct Point{    int x,y;    Point(){}    Point( int xx, int yy)    {        x = xx, y = yy;    }    Point operator - ( const Point &p)const    {        return Point(x-p.x,y-p.y);    }    int operator ^ ( const Point &p)const    {        return x*p.y-p.x*y;    }};Point p[maxn];int stack[maxn],top;//计算叉积 p0p1×p0p2int xmult( Point p0, Point p1, Point p2){    return (p1-p0)^(p2-p0);}double sqr( double x){    return x*x;}//求两点之间的距离double dis( Point p1, Point p2){    return sqrt(sqr((double)(p1.x-p2.x))+sqr((double)(p1.y-p2.y)));}//极角排序,角度相同距离小的在前面bool cmp( Point p1, Point p2){    int tmp = xmult(p[0],p1,p2);    if( tmp > 0)//tmp大于0,说明p1在p2的右边,也就是p1的极角小于p2的极角        return true;    else if( tmp == 0 && dis(p[0],p1) < dis(p[0],p2))//极角相同且p1距p[0]近        return true;    else        return false;}void graham( int n){    if( n == 1)    {        top = 0;        stack[0] = 0;    }    if( n == 2)    {        top = 1;        stack[0] = 0;        stack[1] = 1;    }    if( n > 2)    {        stack[0] = 0, stack[1] = 1, top = 1;        for( int i = 2; i < n; i++)        {            //判断栈顶的点是否在凸包上,当前点p[i]如果在p[stack[top-1]]p[stack[top]]左边,栈顶在凸包上,右边栈顶不在凸包上            while( top > 0 && xmult(p[stack[top-1]],p[stack[top]],p[i]) <= 0)                top--;            top++;            stack[top] = i;        }    }}int main(){    while( ~scanf("%d%d",&n,&l))    {        Point p0;        scanf("%d%d",&p[0].x,&p[0].y);        p0.x = p[0].x, p0.y = p[0].y;        int k = 0;        for( int i = 1; i < n; i++)        {            scanf("%d%d",&p[i].x,&p[i].y);            if( p0.y > p[i].y || ( p0.y == p[i].y && p0.x > p[i].x))//找到纵坐标最小的点,如果有多个纵坐标相同的话,取最左                p0.x = p[i].x, p0.y = p[i].y , k = i;        }        p[k] = p[0];        p[0] = p0;        sort(p+1,p+n,cmp);//按极角大小对点进行排序        graham(n);        double ans = 0;        for( int i = 0; i < top; i++)            ans += dis(p[stack[i]],p[stack[i+1]]);        ans += dis(p[stack[0]],p[stack[top]]);        ans += 2*PI*l;        printf("%d\n",(int)(ans+0.5));    }    return 0;}