BZOJ
1185: [HNOI2007]最小矩形覆盖
Time Limit: 10 Sec Memory Limit: 162 MBSec Special JudgeSubmit: 430 Solved: 202
[Submit][Status]
Description
#include"stdio.h" #include"string.h" #include"math.h" #define M 50006 #define eps 1e-10 #include"stdlib.h" #define inf 999999999 typedef struct node { double x,y,dis,cos; }P; P p[M],q[M],pp[M]; double min(double a,double b) { return a<b?a:b; } int cmp(const void *a,const void *b) { if(fabs((*(struct node*)a).cos-(*(struct node*)b).cos)<eps) return (*(struct node*)a).dis>(*(struct node*)b).dis?1:-1; else return (*(struct node*)b).cos>(*(struct node*)a).cos?1:-1; } double pow(double x) { return x*x; } double Len(node p0,node p1) { return pow(p1.x-p0.x)+pow(p1.y-p0.y); } double COS(node p0,node p1) { double x1=p1.x-p0.x; double y1=p1.y-p0.y; double x2=1; double y2=0; return (x1*x2+y1*y2)/sqrt((x1*x1+y1*y1)*(x2*x2+y2*y2)); } double cross(node p0,node p1,node p2) { double x1=p1.x-p0.x; double y1=p1.y-p0.y; double x2=p2.x-p0.x; double y2=p2.y-p0.y; return x1*y2-x2*y1; } double dot(node p0,node p1,node p2) { double x1=p1.x-p0.x; double y1=p1.y-p0.y; double x2=p2.x-p1.x; double y2=p2.y-p1.y; return x1*x2+y1*y2; } node miss(node q1,double a,double b,node q2)//求两直线交点坐标 { node ret; double c1=a*q1.y-b*q1.x; double c2=-a*q2.x-b*q2.y; ret.x=-(b*c1+a*c2)/(a*a+b*b); ret.y=(a*c1-b*c2)/(a*a+b*b); return ret; } int main() { int n,i,j; while(scanf("%d",&n)!=-1) { node start; int tep; start.x=start.y=inf; for(i=0;i<n;i++) { scanf("%lf%lf",&p[i].x,&p[i].y); if(start.y>p[i].y) { start=p[i]; tep=i; } else if(fabs(start.y-p[i].y)<eps) { if(start.x>p[i].x) { start=p[i]; tep=i; } } } p[tep].dis=0; p[tep].cos=1.0; for(i=0;i<n;i++) { if(i!=tep) { if(fabs(p[i].x-start.x)<eps&&fabs(p[i].y-start.y)<eps) { p[i].dis=0; p[i].cos=1.0; } else { p[i].dis=Len(start,p[i]); p[i].cos=COS(start,p[i]); } } } qsort(p,n,sizeof(p[0]),cmp); int tt=0; for(i=0;i<n;i++) { if(fabs(p[i].cos-p[(i+1)%n].cos)>eps||fabs(p[i].dis-p[(i+1)%n].dis)>eps) pp[tt++]=p[i]; } if(tt==0) { printf("%.5lf ",0.0); for(i=0;i<4;i++) printf("%.5lf %.5lf ",p[0].x,p[0].y); continue; } int flag=0; for(i=1;i<tt-1;i++) { if(fabs(p[i].cos-p[i+1].cos)>eps) flag++; } if(!flag) { printf("%.5lf ",0.0); printf("%.5lf %.5lf ",pp[0].x,pp[0].y); printf("%.5lf %.5lf ",pp[tt-1].x,pp[tt-1].y); printf("%.5lf %.5lf ",pp[tt-1].x,pp[tt-1].y); printf("%.5lf %.5lf ",pp[0].x,pp[0].y); continue; } q[0]=pp[tt-1];//注意tt; q[1]=pp[0]; q[2]=pp[1]; int cnt=2; for(i=2;i<tt;i++) { while(cross(q[cnt-1],q[cnt],pp[i])<0) { cnt--; } q[++cnt]=pp[i]; } int k1,k2; k1=1; j=1; double S=inf; double a[5],b[5]; int indx[5]; for(i=0;i<cnt;i++) { double w=sqrt(Len(q[i],q[(i+1)%cnt])); while(cross(q[i],q[(i+1)%cnt],q[(j+1)%cnt])>cross(q[i],q[(i+1)%cnt],q[j%cnt])) { j++; } double high=cross(q[i],q[(i+1)%cnt],q[j%cnt])/w; while(dot(q[i],q[(i+1)%cnt],q[(k1+1)%cnt])>dot(q[i],q[(i+1)%cnt],q[(k1)%cnt])) { k1++; } if(i==0) k2=k1; while(dot(q[i],q[(i+1)%cnt],q[(k2+1)%cnt])<=dot(q[i],q[(i+1)%cnt],q[(k2)%cnt])) { k2++; } double wide=(dot(q[i],q[(i+1)%cnt],q[(k1)%cnt])-dot(q[i],q[(i+1)%cnt],q[(k2)%cnt]))/w; if(S>high*wide) { S=high*wide;//更新四个切点坐标以及旋转的直线的方向向量 indx[0]=i; indx[1]=k1%cnt; indx[2]=j%cnt; indx[3]=k2%cnt; a[0]=q[(i+1)%cnt].x-q[i].x; b[0]=q[(i+1)%cnt].y-q[i].y; a[1]=b[0]; b[1]=-a[0]; a[2]=a[0]; b[2]=b[0]; a[3]=b[0]; b[3]=-a[0]; } } printf("%.5lf ",S); node ret[5]; start.x=start.y=inf; for(i=0;i<4;i++)//先找出左下角的点的坐标然后按照极角排序 { ret[i]=miss(q[indx[i]],a[i],b[i],q[indx[(i+1)%4]]); //printf("%.5lf %.5lf ",ret[i].x,ret[i].y); if(start.y>ret[i].y) { start=ret[i]; tep=i; } else if(fabs(start.y-ret[i].y)<eps) { if(start.x>ret[i].x) { start=ret[i]; tep=i; } } } ret[tep].dis=0; ret[tep].cos=1.5; for(i=0;i<4;i++) { if(i!=tep) { ret[i].dis=Len(start,ret[i]); ret[i].cos=COS(start,ret[i]); } } qsort(ret,4,sizeof(ret[0]),cmp); for(i=0;i<4;i++) printf("%.5lf %.5lf ",ret[i].x,ret[i].y); } return 0; }