半平面交 求解最大内接圆

上图使用来描述直线向内推进r这一过程的ac=r,ae是推进前的直线上的两点,现在求c、f的坐标,

由上可得三角形ace  与三角形abd相似,所以很快便可求出ab 的距离,即x坐标的移动距离,延长de,

从f向其做垂线,连接fd,便又可以由三角形相似求得y坐标的移动距离

 

下面是两道半平面交向内推进r的例子

http://poj.org/problem?id=3525

http://poj.org/problem?id=3384

主要讲讲3384

先用3525的方法向内推进r求出一个内核,则可知这个核上的任何一点都可以成为圆心坐标,要使的两个圆的重叠面积尽可能小,

就要使他们的圆心坐标尽可能的远,素以可以选取内核上最远的两个点作为圆心

 

View Code
#include <cmath>
#include <cstring>
#include <cstdio>
#include<algorithm>
using namespace std;
const double INF = 1000000000.0;
const int maxn = 1010;
const double eps = 1e-8;
inline double sgn(double x) {return fabs(x)<eps?0:(x>0?1:-1);}
struct Point{
double x,y;
Point(double tx=0,double ty=0){x=tx;y=ty;}
bool operator == (const Point& t) const {
return sgn(x-t.x)==0 && sgn(y-t.y)==0;
}
}p[maxn],st[maxn],pp[maxn],points[maxn];
struct Seg{Point s,e;};
double dist(Point a,Point b){return (a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y);}
double cross(Point a,Point b,Point c){return (b.x-a.x)*(c.y-a.y)-(b.y-a.y)*(c.x-a.x);}
bool outside(Seg seg,Point p){return cross(seg.s,seg.e,p)>eps;}//strictly outside the ploygon
bool inside(Seg seg,Point p){return cross(seg.s,seg.e,p)<-eps;}//strictly inside the ploygon
Point Intersect(Point p1, Point p2, Point p3, Point p4) {
double a1, b1, c1, a2, b2, c2, d;Point p;
a1 = p1.y - p2.y; b1 = p2.x - p1.x; c1 = p1.x*p2.y - p2.x*p1.y;
a2 = p3.y - p4.y; b2 = p4.x - p3.x; c2 = p3.x*p4.y - p4.x*p3.y;
d = a1*b2 - a2*b1;
if ( fabs(d) < eps ) return false;
p.x = (-c1*b2 + c2*b1) / d;
p.y = (-a1*c2 + a2*c1) / d;
return p;
}
int n,ban_tot;
void CUT(Seg seg){//p must be clockwise
int i,tot=0;
for(i=1;i<=ban_tot;i++){
if(!outside(seg,p[i])) pp[++tot]=p[i];//p[i] :inside or on the boundary
else {//p[i]: must be outside
if(inside(seg,p[i-1])) pp[++tot]=Intersect(seg.s,seg.e,p[i],p[i-1]);//p[i-1] must be inside
if(inside(seg,p[i+1])) pp[++tot]=Intersect(seg.s,seg.e,p[i],p[i+1]);//p[i+1] must be inside
}
}ban_tot=tot;
pp[tot+1]=pp[1];pp[0]=pp[tot];
memcpy(p,pp,sizeof(pp));
}
void solve(double r){ //push length r inside
memcpy(p,points,sizeof(points)); ban_tot=n;//don't forget initialize
for(int i = 1; i <= n; ++i){
Point ta, tb, tt;
tt.x = points[i+1].y-points[i].y;
tt.y = points[i].x-points[i+1].x;
double k = r / sqrt(tt.x * tt.x + tt.y * tt.y);
tt.x = tt.x * k; tt.y = tt.y * k;
ta.x = points[i].x + tt.x; ta.y = points[i].y + tt.y;
tb.x = points[i+1].x + tt.x; tb.y = points[i+1].y + tt.y;
Seg seg;seg.s=ta,seg.e=tb;
CUT(seg);
}
}
Seg ts[110];
int main(){
int i;double r;
scanf("%d%lf",&n,&r);
for(i=1;i<=n;i++) scanf("%lf%lf",&points[i].x,&points[i].y);
points[n+1]=points[1];ban_tot=n;points[0]=points[n];
solve(r);//printf("tot=%d\n",ban_tot);
double ans=0;
int a=1,b=1;//printf("%.3lf %.4lf\n",p[1].x,p[1].y);
for(i=1;i<=ban_tot;i++)
{
for(int j=i+1;j<=ban_tot;j++)
{
if(dist(p[i],p[j])>ans)
{
a=i;
b=j;
ans=dist(p[i],p[j]);
}
}
}
printf("%.4lf %.4lf %.4lf %.4lf\n",p[a].x,p[a].y,p[b].x,p[b].y);
return 0;
}



posted @ 2012-04-01 00:51  Because Of You  Views(382)  Comments(0Edit  收藏  举报