poj 1113 Wall (andrew,graham求凸包)

版权声明:转载注明下出处就行了。 https://blog.csdn.net/LJD201724114126/article/details/83932639

题目链接:poj 1113

参考博客:https://www.cnblogs.com/kuangbin/archive/2012/04/13/2445633.html

https://www.cnblogs.com/acgoto/p/9547049.html

题意:给出n个点,让你把这n个点围起来,有个前提,围墙到顶点的距离要等于L,问围墙有多长。

题解搬kuangbin神犇的。

题解:这道题的答案是凸包周长加上一个圆周长,即包围凸包的一个圆角多边形,但是没弄明白那些圆角加起来为什么恰好是一个圆。每个圆角是以凸包对应的顶点为圆心,给定的L为半径,与相邻两条边的切点之间的一段圆弧。每个圆弧的两条半径夹角与对应的凸包的内角互补。假设凸包有n条边,则所有圆弧角之和为180°*n-180°*(n-2)=360°。故,围墙周长为=n条平行于凸包的线段+n条圆弧的长度=凸包周长+围墙离城堡距离L为半径的圆周长。

代码:

andrew算法和graham算法求凸包,紫薯上说andrew更快,数值稳定性更好,因为andrew算法只是按照坐标排序,不同于graham算法,是按极角排序,大量用叉积比较。

///andrew 求凸包 首尾相同

#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>

using namespace std;
const int maxn=1010;
const double PI=acos(-1.0);

struct point{
    int x,y;
    point(){}
    point(int _x,int _y){
        x=_x;y=_y;
    }
}p[maxn],ch[maxn];

point operator + (point a,point b) {return point(a.x+b.x,a.y+b.y);}
point operator - (point a,point b) {return point(a.x-b.x,a.y-b.y);}
point operator * (point a,int p) { return point(a.x*p,a.y*p);}
point operator / (point a,int p){ return point(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);
}
const double esp=1e-8;
int dcmp(double x){
    if(fabs(x)<esp) return 0;
    else return x<0?-1:1;
}
bool operator ==(const point &a,const point &b){
    return dcmp(a.x-b.x)==0&&dcmp(a.y-b.y)==0;
}

int Cross(point a,point b) { return a.x*b.y-a.y*b.x;}
double Length(point a) { return sqrt(a.x*a.x*1.0+a.y*a.y*1.0);}

bool cmp(point a,point b) ///坐标排序
{
    return (a.y<b.y||(a.y==b.y&&a.x<b.x));
}

int tot;
void andrew(int n)
{

    sort(p,p+n,cmp);

    tot=-1;
    for(int i=0;i<n;i++) ///构造凸包下侧
    {
        while(tot>0&&Cross(ch[tot]-ch[tot-1],p[i]-ch[tot-1])<=0)
            tot--;
        ch[++tot]=p[i];
    }

    for(int i=n-2,k=tot;i>=0;i--){ ///构造凸包上侧
        while(tot>k&&Cross(ch[tot]-ch[tot-1],p[i]-ch[tot-1])<=0)
            tot--;
        ch[++tot]=p[i];
    }
}

int main()
{
        int N,L;
        while(~scanf("%d%d",&N,&L))
        {

            for(int i=0;i<N;i++)
            {
                scanf("%d%d",&p[i].x,&p[i].y);
            }

            andrew(N);


            double sum=0;

            for(int i=0;i<tot;i++){
                sum+=Length(ch[i+1]-ch[i]);
            }
            sum+=Length(ch[tot]-ch[0]);

            sum+=2*PI*L;

            printf("%d\n",(int)(sum+0.5));

        }
        return 0;
}

///graham求凸包 首尾不同

#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>

using namespace std;
const int maxn=1010;
const double PI=acos(-1.0);

struct point{
    int x,y;
    point(){}
    point(int _x,int _y){
        x=_x;y=_y;
    }
}node[maxn];

point operator + (point a,point b) {return point(a.x+b.x,a.y+b.y);}
point operator - (point a,point b) {return point(a.x-b.x,a.y-b.y);}
point operator * (point a,int p) { return point(a.x*p,a.y*p);}
point operator / (point a,int p){ return point(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);
}
const double esp=1e-8;
int dcmp(double x){
    if(fabs(x)<esp) return 0;
    else return x<0?-1:1;
}
bool operator ==(const point &a,const point &b){
    return dcmp(a.x-b.x)==0&&dcmp(a.y-b.y)==0;
}

int Cross(point a,point b) { return a.x*b.y-a.y*b.x;}
double Length(point a) { return sqrt(a.x*a.x+a.y*a.y);}

point p0; ///以p0为根据
bool cmp(point a,point b) ///极角排序函数,角度相同则距离小的在前面
{
    int tmp=Cross(a-p0,b-p0);
    if(tmp>0) return true;
    else if(tmp==0&&dcmp(Length(a-p0)-Length(b-p0))<0)
        return true;
    else return false;
}

int num[maxn],tot;

void graham(int n)
{
    tot=0;

    if(n==1){
        tot=0;num[0]=0;
    }

    if(n==2){
        tot=1;num[0]=0;num[1]=1;
    }

    if(n>2){
        tot=1;num[0]=0;num[1]=1;

        for(int i=2;i<n;i++)
        {
            while(tot>0&&Cross(node[num[tot]]-node[num[tot-1]],node[i]-node[num[tot-1]])<=0)
                tot--;
            num[++tot]=i;
        }
    }
}


int main()
{
        int N,L;
        while(~scanf("%d%d",&N,&L))
        {

            scanf("%d%d",&node[0].x,&node[0].y);

            int k=0;
            p0=point(node[0].x,node[0].y);

            for(int i=1;i<N;i++)
            {
                scanf("%d%d",&node[i].x,&node[i].y);

                if(p0.y>node[i].y||((p0.y==node[i].y)&&(p0.x>node[i].x))){
                    p0=node[i];
                    k=i;
                }
            }

            node[k]=node[0];
            node[0]=p0;
            sort(node+1,node+N,cmp);

            graham(N);


            double sum=0;
            for(int i=0;i<tot;i++){
                sum+=Length(node[num[i]]-node[num[i+1]]);
            }
            sum+=Length(node[num[tot]]-node[num[0]]);

            sum+=2*PI*L;

            printf("%d\n",(int)(sum+0.5));

        }
        return 0;
}

猜你喜欢

转载自blog.csdn.net/LJD201724114126/article/details/83932639