[uva]10135 - Herding Frosh

[uva]10135 - Herding Frosh

【题目】http://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=1076

【题意】求凸包边长最小的值,要求原点在凸包上。

【算法】枚举凸包

【题解】将坐标按左下优先排序,然后删出重复点,按原点的极角[0-360)排序,删除在同一极角上的点(只保留最外面的)。然后枚举出所有原点出发后结束的凸包,比较得出最小值。

【细节】角度的浮点数判等。同一直线上,重点等等。

【测试】

100
4
1 1
-1 1
1 -1
-1 -1
2
-1 -1
1 1
2
1 1
2 2
5
1 1
1.1 1.1
2 2
3.3 3.3
4.4 4.4

11
1 1
-1 1
1 -1
-1 -1
0.1 1
0.3 0.5
-0.2 0.3
-0.3 -0.2
0.2 0.2
-0.1 -0.1
0.7 -0.35

 

ans:

10.83

 

7.66

 

7.66

 

14.45

 

10.83

 

 

 

【代码】

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;

#define EPS (1E-10)

struct point{
    double x,y;
}p[1010],h[1010];

double are_triangle(point a,point b,point c){
    return a.x*b.y+b.x*c.y+c.x*a.y-a.x*c.y-b.x*a.y-c.x*b.y;
}

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

double pi=4.0*atan(1.0);

double J_angle(point a){
    if(a.y==0.0&&a.x>=0.0)return 0;
    point ori,p1;
    p1.y=ori.x=ori.y=0;
    p1.x=1;
    if(a.y>0)
    return acos((di(a,ori)*di(a,ori)+1-di(a,p1)*di(a,p1))/(2*di(a,ori)));
    return 2*pi-acos((di(a,ori)*di(a,ori)+1-di(a,p1)*di(a,p1))/(2*di(a,ori)));
}

 

int leftlower(point a,point b){
    if(a.x!=b.x)return a.x<b.x;
    return a.y<b.y;
}

int small_angle(point a,point b){
    //if(are_triangle(first,a,b)==0)return di(first,a)<di(first,b);
    //return are_triangle(first,a,b)<0;
    if(fabs(J_angle(a)-J_angle(b))>EPS)return J_angle(a)<J_angle(b);
    //printf("!!\n");
    return (a.x*a.x+a.y*a.y)<(b.x*b.x+b.y*b.y);
}

void copy_point(point *a,point *b){
    a->x=b->x;
    a->y=b->y;
}

void sort_remove(int *n){
    int i,oldn=*n,j;
    sort(p,p+oldn,leftlower);
    if(p[0].x==0&&p[0].y==0){
        *n=*n-1;
        j=0;
    }
    else j=1;
    for(i=1;i<oldn;i++){
        if((p[i].x==p[i-1].x&&p[i].y==p[i-1].y)||(p[i].x==0&&p[i].y==0))*n=*n-1;
        else  copy_point(&p[j++],&p[i]);
    }
}
void remove_com(int *n){
    int old = *n,j=0,i;

    for(i=1;i<old;i++){
        if(fabs(J_angle(p[i])-J_angle(p[j]))<=EPS){
            copy_point(&p[j],&p[i]);
            *n=*n-1;
        }
        else copy_point(&p[++j],&p[i]);
    }

}

double fun(int n){
    int i,j,hn,top;
    double min=-1,s;
    point ori;
    ori.x=ori.y=0;
    sort_remove(&n);
    if(n==0)return 0;
    if(n==1)return 2.0*di(ori,p[0]);
    if(n==2) return di(p[0],p[1])+di(ori,p[0])+di(ori,p[1]);
    sort(p,p+n,small_angle);
    //printf("n=%d\n",n);
    //for(i=0;i<n;i++)printf("%.2f %.2f\n",p[i].x,p[i].y);
    remove_com(&n);
    if(n==0)return 0;
    if(n==1)return 2.0*di(ori,p[0]);
    if(n==2) return di(p[0],p[1])+di(ori,p[0])+di(ori,p[1]);
  //   printf("n=%d\n",n);
  //  for(i=0;i<n;i++)printf("%.2f %.2f\n",p[i].x,p[i].y);

    copy_point(&p[n],&ori);
    for(i=0;i<n;i++){
        copy_point(&h[0],&ori);
        copy_point(&h[1],&p[i]);
        j=(i+1)%n;
        top=1;
        //printf("_______________________-\n");
        while(j!=i){
            //printf("%d %d\n",top,i);
            //printf("%f %f %f\n",are_triangle(h[top-1],h[top],p[j]),p[j].x,p[j].y);
            //printf("%f\n",(p[j].x-h[top-1].x)*(p[j].x-h[top].x));
            //if((are_triangle(h[top-1],h[top],p[j])==0&&(p[j].x-h[top-1].x)*(p[j].x-h[top].x)>=0))printf("!!\n");
            //else printf("??\n");
            //getchar();
            if(are_triangle(h[top-1],h[top],p[j])<0||(are_triangle(h[top-1],h[top],p[j])==0&&(p[j].x-h[top-1].x)*(p[j].x-h[top].x)>=0)){
                top--;
                if(top<=0)break;
            }
            else {
                top++;
                copy_point(&h[top],&p[j]);
                j=(j+1)%n;
            }
        }
        if(top<=0)continue;
        //while(are_triangle(h[top-1],h[top],p[n])<0||(are_triangle(h[top-1],h[top],p[n])==0&&(p[n].x-h[top-1].x)*(p[n].x-h[top].x)>=0)){
        //        top--;
        //        if(top<=0)break;
        //}
        //if(top<=0)continue;
        hn=top+1;
        s=di(h[hn-1],ori);
        //printf("i=%d hn=%d\n",i,hn);
        //for(j=0;j<hn;j++)printf("%.2f %.2f\n",h[j].x,h[j].y);
        for(j=1;j<hn;j++)s+=di(h[j],h[j-1]);
        //printf("%.2f %.2f\n",min,s);
        if(min==-1||min>s)min=s;
    }
    return min;
}

 

int main(){
    int T,n,i,j=0;
    scanf("%d",&T);
    //point zz;
    //double a,b;
    //zz.x=zz.y=1;
    //printf("%f\n",(a=J_angle(zz)));
    //zz.x=zz.y=0.2;
    //printf("%f\n",(b=J_angle(zz)));
    //if(a!=b)printf("!!\n");
    //else printf("??\n");

    while(T-->0){
        if(j==0)j=1;
        else putchar('\n');
        scanf("%d",&n);
        for(i=0;i<n;i++)scanf("%lf%lf",&p[i].x,&p[i].y);
        printf("%.2f\n",(double)((int)((fun(n)+2.005)*100))/100.0);
    }

    return 0;
}

【心得】我的第一个凸包啊。好辛苦。

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值