1. 程式人生 > >BZOJ 1185: [HNOI2007]最小矩形覆蓋-旋轉卡殼法求點集最小外接矩形(面積)並輸出四個頂點坐標-備忘板子

BZOJ 1185: [HNOI2007]最小矩形覆蓋-旋轉卡殼法求點集最小外接矩形(面積)並輸出四個頂點坐標-備忘板子

article ref https color 旋轉 blank spa def abs

來源:旋轉卡殼法求點集最小外接矩形(面積)並輸出四個頂點坐標

BZOJ又崩了,直接貼一下人家的代碼。

代碼:

  1 #include"stdio.h"
  2 #include"string.h"
  3 #include"math.h"
  4 #define M 50006
  5 #define eps 1e-10
  6 #include"stdlib.h"
  7 #define inf 999999999
  8 typedef struct node
  9 {
 10     double x,y,dis,cos;
 11 }P;
 12
P p[M],q[M],pp[M]; 13 double min(double a,double b) 14 { 15 return a<b?a:b; 16 } 17 int cmp(const void *a,const void *b) 18 { 19 if(fabs((*(struct node*)a).cos-(*(struct node*)b).cos)<eps) 20 return (*(struct node*)a).dis>(*(struct node*)b).dis?1:-1; 21 else
22 return (*(struct node*)b).cos>(*(struct node*)a).cos?1:-1; 23 24 } 25 double pow(double x) 26 { 27 return x*x; 28 } 29 double Len(node p0,node p1) 30 { 31 return pow(p1.x-p0.x)+pow(p1.y-p0.y); 32 } 33 double COS(node p0,node p1) 34 { 35 double x1=p1.x-p0.x;
36 double y1=p1.y-p0.y; 37 double x2=1; 38 double y2=0; 39 return (x1*x2+y1*y2)/sqrt((x1*x1+y1*y1)*(x2*x2+y2*y2)); 40 } 41 double cross(node p0,node p1,node p2) 42 { 43 double x1=p1.x-p0.x; 44 double y1=p1.y-p0.y; 45 double x2=p2.x-p0.x; 46 double y2=p2.y-p0.y; 47 return x1*y2-x2*y1; 48 } 49 double dot(node p0,node p1,node p2) 50 { 51 double x1=p1.x-p0.x; 52 double y1=p1.y-p0.y; 53 double x2=p2.x-p1.x; 54 double y2=p2.y-p1.y; 55 return x1*x2+y1*y2; 56 } 57 node miss(node q1,double a,double b,node q2)//求兩直線交點坐標 58 { 59 node ret; 60 double c1=a*q1.y-b*q1.x; 61 double c2=-a*q2.x-b*q2.y; 62 ret.x=-(b*c1+a*c2)/(a*a+b*b); 63 ret.y=(a*c1-b*c2)/(a*a+b*b); 64 return ret; 65 } 66 int main() 67 { 68 int n,i,j; 69 while(scanf("%d",&n)!=-1) 70 { 71 node start; 72 int tep; 73 start.x=start.y=inf; 74 for(i=0;i<n;i++) 75 { 76 scanf("%lf%lf",&p[i].x,&p[i].y); 77 if(start.y>p[i].y) 78 { 79 start=p[i]; 80 tep=i; 81 } 82 else if(fabs(start.y-p[i].y)<eps) 83 { 84 if(start.x>p[i].x) 85 { 86 start=p[i]; 87 tep=i; 88 } 89 } 90 } 91 p[tep].dis=0; 92 p[tep].cos=1.0; 93 for(i=0;i<n;i++) 94 { 95 if(i!=tep) 96 { 97 if(fabs(p[i].x-start.x)<eps&&fabs(p[i].y-start.y)<eps) 98 { 99 p[i].dis=0; 100 p[i].cos=1.0; 101 } 102 else 103 { 104 p[i].dis=Len(start,p[i]); 105 p[i].cos=COS(start,p[i]); 106 } 107 } 108 } 109 qsort(p,n,sizeof(p[0]),cmp); 110 int tt=0; 111 for(i=0;i<n;i++) 112 { 113 if(fabs(p[i].cos-p[(i+1)%n].cos)>eps||fabs(p[i].dis-p[(i+1)%n].dis)>eps) 114 pp[tt++]=p[i]; 115 } 116 if(tt==0) 117 { 118 printf("%.5lf\n",0.0); 119 for(i=0;i<4;i++) 120 printf("%.5lf %.5lf\n",p[0].x,p[0].y); 121 continue; 122 } 123 int flag=0; 124 for(i=1;i<tt-1;i++) 125 { 126 if(fabs(p[i].cos-p[i+1].cos)>eps) 127 flag++; 128 } 129 if(!flag) 130 { 131 printf("%.5lf\n",0.0); 132 printf("%.5lf %.5lf\n",pp[0].x,pp[0].y); 133 printf("%.5lf %.5lf\n",pp[tt-1].x,pp[tt-1].y); 134 printf("%.5lf %.5lf\n",pp[tt-1].x,pp[tt-1].y); 135 printf("%.5lf %.5lf\n",pp[0].x,pp[0].y); 136 continue; 137 } 138 q[0]=pp[tt-1];//註意tt; 139 q[1]=pp[0]; 140 q[2]=pp[1]; 141 int cnt=2; 142 for(i=2;i<tt;i++) 143 { 144 while(cross(q[cnt-1],q[cnt],pp[i])<0) 145 { 146 cnt--; 147 } 148 q[++cnt]=pp[i]; 149 } 150 int k1,k2; 151 k1=1; 152 j=1; 153 double S=inf; 154 double a[5],b[5]; 155 int indx[5]; 156 for(i=0;i<cnt;i++) 157 { 158 double w=sqrt(Len(q[i],q[(i+1)%cnt])); 159 while(cross(q[i],q[(i+1)%cnt],q[(j+1)%cnt])>cross(q[i],q[(i+1)%cnt],q[j%cnt])) 160 { 161 j++; 162 } 163 double high=cross(q[i],q[(i+1)%cnt],q[j%cnt])/w; 164 while(dot(q[i],q[(i+1)%cnt],q[(k1+1)%cnt])>dot(q[i],q[(i+1)%cnt],q[(k1)%cnt])) 165 { 166 k1++; 167 } 168 if(i==0) 169 k2=k1; 170 while(dot(q[i],q[(i+1)%cnt],q[(k2+1)%cnt])<=dot(q[i],q[(i+1)%cnt],q[(k2)%cnt])) 171 { 172 k2++; 173 } 174 double wide=(dot(q[i],q[(i+1)%cnt],q[(k1)%cnt])-dot(q[i],q[(i+1)%cnt],q[(k2)%cnt]))/w; 175 if(S>high*wide) 176 { 177 S=high*wide;//更新四個切點坐標以及旋轉的直線的方向向量 178 indx[0]=i; 179 indx[1]=k1%cnt; 180 indx[2]=j%cnt; 181 indx[3]=k2%cnt; 182 a[0]=q[(i+1)%cnt].x-q[i].x; 183 b[0]=q[(i+1)%cnt].y-q[i].y; 184 a[1]=b[0]; 185 b[1]=-a[0]; 186 a[2]=a[0]; 187 b[2]=b[0]; 188 a[3]=b[0]; 189 b[3]=-a[0]; 190 } 191 } 192 printf("%.5lf\n",S); 193 node ret[5]; 194 start.x=start.y=inf; 195 196 for(i=0;i<4;i++)//先找出左下角的點的坐標然後按照極角排序 197 { 198 ret[i]=miss(q[indx[i]],a[i],b[i],q[indx[(i+1)%4]]); 199 //printf("%.5lf %.5lf\n",ret[i].x,ret[i].y); 200 if(start.y>ret[i].y) 201 { 202 start=ret[i]; 203 tep=i; 204 } 205 else if(fabs(start.y-ret[i].y)<eps) 206 { 207 if(start.x>ret[i].x) 208 { 209 start=ret[i]; 210 tep=i; 211 } 212 213 } 214 } 215 ret[tep].dis=0; 216 ret[tep].cos=1.5; 217 for(i=0;i<4;i++) 218 { 219 if(i!=tep) 220 { 221 ret[i].dis=Len(start,ret[i]); 222 ret[i].cos=COS(start,ret[i]); 223 } 224 } 225 qsort(ret,4,sizeof(ret[0]),cmp); 226 for(i=0;i<4;i++) 227 printf("%.5lf %.5lf\n",ret[i].x,ret[i].y); 228 } 229 return 0; 230 }

整理。

BZOJ 1185: [HNOI2007]最小矩形覆蓋-旋轉卡殼法求點集最小外接矩形(面積)並輸出四個頂點坐標-備忘板子