码迷,mamicode.com
首页 > 其他好文 > 详细

UVALive - 6859 Points

时间:2017-10-15 19:30:05      阅读:195      评论:0      收藏:0      [点我收藏+]

标签:min   int   标记   +=   for   abs   double   val   ace   

题意:给你n个点,然后在方格纸上只能选取边或者对角线,求围住所有点的最小周长

 

题解:根据样例可以发现一个规律,你把制定点的上下左右点都标出来,会发现这是围城一个点的最小距离,这样把所有的点都标记出来,求一下凸包(本人习惯kuangbin板子,但忘了凸包的时间复杂度了,以为会超时,谁知道没有),凸包的算法求出来的是点,这些点被压栈了,在计算距离的时候,只需要按照题目意思,尽量多选择对角线,连起来就可以了。

#include <bits/stdc++.h>
using namespace std;
const double eps=1e-8;
int sgn(double x)
{
    if(fabs(x)<eps) return 0;
    if(x<0) return -1;
    else return 1;
}
struct point
{
    double x,y;
    point (){}
    point (double _x,double _y)
    {
        x=_x,y=_y;
    }
    point operator -(const point &b)const
    {
        return point(x-b.x,y-b.y);
    }
    double operator ^(const point &b)const
    {
        return x*b.y-y*b.x;
    }
    double operator *(const point &b)const
    {
        return x*b.x+y*b.y;
    }
};
const int maxn=1e5+5;
point List[4*maxn];
int Stack[4*maxn],top;
double dist(point p0,point p1)
{
    return (double)sqrt((p0.x-p1.x)*(p0.x-p1.x)+(p0.y-p1.y)*(p0.y-p1.y));
}
bool cmp(point p1,point p2)
{
    double tmp = (p1-List[0])^(p2-List[0]);
    if(sgn(tmp) > 0)return true;
    else if(sgn(tmp) == 0 && sgn(dist(p1,List[0]) - dist(p2,List[0])) <= 0)
        return true;
    else return false;
}
void Graham(int n)
{
    point p0;
    int k = 0;
    p0 = List[0];
    for(int i = 1; i < n; i++){
        if((p0.y>List[i].y)||(p0.y==List[i].y&&p0.x>List[i].x)){
            p0 = List[i];
            k = i;
        }
    }
    swap(List[k],List[0]);
    sort(List+1,List+n,cmp);
    Stack[0] = 0;
    Stack[1] = 1;
    top = 2;
    for(int i = 2; i < n; i++){
        while(top > 1 &&sgn((List[Stack[top-1]]-List[Stack[top-2]])^(List[i]-List[Stack[top-2]]))<=0)
                top--;
        Stack[top++] = i;
    }
}
point as[maxn];
double dist2(point p0,point p1)
{
    double as=fabs(p0.x-p1.x);
    double qw=fabs(p0.y-p1.y);
    return fabs(as-qw)+min(as,qw)*sqrt(2);
}
int main()
{
    int n;
    while(~scanf("%d",&n))
    {
        double t1,t2;
        memset(as,0,sizeof(as));
        for(int i=0;i<n;i++){
            scanf("%lf%lf",&t1,&t2);
            as[i]=point(t1,t2);
        }
        for(int i=0;i<n;i++){
            List[4*i+0]=point(as[i].x-1,as[i].y);
            List[4*i+1]=point(as[i].x+1,as[i].y);
            List[4*i+2]=point(as[i].x,as[i].y+1);
            List[4*i+3]=point(as[i].x,as[i].y-1);
        }
        n*=4;
        Graham(n);
        double res=0.0;
        for(int i=0; i<top-1; i++)
            res+=dist2(List[Stack[i]],List[Stack[i+1]]);
        res+=dist2(List[Stack[0]],List[Stack[top-1]]);
        printf("%.4f\n",res);
    }
    return 0;
}
/*
1
0 0
2
1 1
1 2
*/

 

UVALive - 6859 Points

标签:min   int   标记   +=   for   abs   double   val   ace   

原文地址:http://www.cnblogs.com/lalalatianlalu/p/7672700.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!