zoukankan      html  css  js  c++  java
  • 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 }
  • 相关阅读:
    java类的继承
    Java数组运算
    Eclipse问题提示
    oracle的insert的时候&符号如何插入(转义)
    修改数据库用户名--CMD环境执行有效
    java环境变量设置
    当前时间时间戳以及10分钟后的时间戳
    复选框事件
    分享到
    多物体运动
  • 原文地址:https://www.cnblogs.com/zxj015/p/2740211.html
Copyright © 2011-2022 走看看