poj 3525 Most Distant Point from the Sea 多边形内切圆
求多边形最大内接圆半径。
半平面交+二分查找:把多边形的每条边向内推R的距离,若变幻之后的仍是一个多边形,说明距离R太小了,若无边说明R过大。
这边有两个纯几何上的问题,就是如果求直线和平移直线。
一、已知两点求直线ax+by+c=0:
已知两点为A(x[i],y[i]),B(x[i+1],y[i+1]),取直线上的另外一点C(x,y),则有:
(x-x[i])/(y-y[i])=(x[i+1]-x[i])/(y[i+1]-y[i]);
化解得:
x(y[i+1]-y[i])+y(x[i]-x[i+1])+x[i+1]y[i]-x[i]y[i+1]=0;
即a=y[i+1]-y[i];
b=x[i]-x[i+1];
c=x[i+1]y[i]-x[i]y[i+1];
二、如何平移直线:
就拿最简单的过原点的直线y=(a/b)x的直线来讲吧(有常数项的直线和它类似)。
该直线的倾斜角tan∠T=a/b;
cos∠T=b/sqrt(a*a+b*b);
sin∠T=a/sqrt(a*a+b*b);
设直线平移了mid的距离,直线上的点(x,y)变幻为(x-x1,y-y1);
x1,y1,mid三边可组成一个以mid为斜边的直角三角形;
且x1=sin∠T*mid=a/sqrt(a*a+b*b)*mid;
y1=cos∠T*mdi=b/sqrt(a*a+b*b)*mid;
这样取原直线上的任意两点做如上的变幻,以新得到的这两点再做直线即可。
1 #include<iostream> 2 #include<cmath> 3 using namespace std; 4 const double pi=acos(-1.0); 5 const int N=500; 6 const double eps=1e-9; 7 int n,m,s; 8 struct point 9 { 10 double x,y; 11 }p[N],q[N],input[N]; 12 int sig(double k) 13 { 14 return (k<-eps)?-1:(k>eps); 15 } 16 double dis(point a,point b) 17 { 18 return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y)); 19 } 20 double xmule(point p1,point p2,point p3) 21 { 22 return ((p2.x-p1.x)*(p3.y-p1.y)-(p3.x-p1.x)*(p2.y-p1.y)); 23 } 24 void interect(point x,point y,double a,double b,double c)//求2直线交点(xy与ax0+by0+c=0的交点) 25 { 26 double u=fabs(a*x.x+b*x.y+c); 27 double v=fabs(a*y.x+b*y.y+c); 28 q[++s].x=(x.x*v+y.x*u)/(u+v); 29 q[s].y=(x.y*v+y.y*u)/(u+v); 30 } 31 void cut(double a,double b,double c)//半平面切割 32 { 33 s=0; 34 int i; 35 for(i=1;i<=m;i++)//枚举所有点 36 { 37 if(sig(a*p[i].x+b*p[i].y+c)>=0)//逆时针时为>=0 38 { 39 q[++s]=p[i];//符合 40 } 41 else 42 { 43 if(sig(a*p[i-1].x+b*p[i-1].y+c)>0) 44 interect(p[i-1],p[i],a,b,c);//p[i]p[i-1]与直线的交点符合 45 if(sig(a*p[i+1].x+b*p[i+1].y+c)>0) 46 interect(p[i],p[i+1],a,b,c);//p[i]p[i+1]与直线的交点符合 47 } 48 } 49 for(i=1;i<=s;i++) 50 { 51 p[i]=q[i];//更新 52 } 53 p[0]=p[s]; 54 p[s+1]=p[1]; 55 m=s; 56 } 57 int main() 58 { 59 //freopen("in.txt","r",stdin); 60 int i,j; 61 double mid; 62 while(scanf("%d",&n)!=EOF&&n) 63 { 64 for(i=1;i<=n;i++) 65 { 66 scanf("%lf%lf",&input[i].x,&input[i].y); 67 p[i]=input[i]; 68 } 69 input[n+1]=input[1]; 70 p[0]=p[n]; 71 p[n+1]=p[1]; 72 double max=-1; 73 for(i=1;i<=n;i++) 74 { 75 for(j=i+1;j<=n;j++) 76 { 77 double temp=dis(p[i],p[j]); 78 if(max<temp)//找2点距离最大的点 79 { 80 max=temp; 81 } 82 } 83 } 84 double l=0, r=max/2; 85 while(r-l>eps)//二分半径 86 { 87 mid=(l+r)/2; 88 double a,b,c; 89 point tt,ta,tb; 90 for(i=1;i<=n;i++) 91 { 92 p[i]=input[i]; 93 } 94 p[0]=p[n]; 95 p[n+1]=p[1]; 96 m=n; 97 for(i=1;i<=n;i++) 98 { 99 tt.x=input[i].y-input[i+1].y;//逆时针,注意顺序,每条边一起向“内”推进R 100 tt.y=input[i+1].x-input[i].x; 101 double k=mid/sqrt(tt.x*tt.x+tt.y*tt.y); 102 tt.x=tt.x*k; 103 tt.y=tt.y*k; 104 ta.x=input[i].x+tt.x; 105 ta.y=input[i].y+tt.y; 106 tb.x=input[i+1].x+tt.x; 107 tb.y=input[i+1].y+tt.y; 108 109 a=ta.y-tb.y;//由2点求出直线ax+by+c=0 110 b=tb.x-ta.x; 111 c=ta.x*tb.y-ta.y*tb.x; 112 cut(a,b,c); 113 } 114 if(m<=2) r=mid; 115 // else if(fabs(xmule(p[1],p[2],p[3]))<eps) r=mid; 116 else l=mid; 117 } 118 printf("%.6lf\n",l); 119 } 120 return 0; 121 }