[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;
}
【心得】我的第一个凸包啊。好辛苦。