HDU - 3644: A Chocolate Manufacturer's Problem (simulated annealing, in seeking the maximum radius polygon)

pro: Given an N-sided polygon, and a circle of radius R, and asked if they could go into. Transformed into the maximum inscribed circle radius of the polygon. (N <50);

sol: At first glance, not that half + half-plane cross verify the nuclear problem of the board it. However, things are not so simple. Because our polygon may be concave polygon, and the previous method is only valid for a convex polygon. 

Studied under simulated annealing algorithm, this random algorithm only written when the smallest circle coverage. Here to learn about, it looks a little more authentic. Every time looking around (R) to optimize the current point of whether, and the R gradually becomes smaller, making the answers tightening trend finer. 

Decision point within the polygon and then: Similarly, if the test can not be used to determine the left each side, because it is not convex polygon; we can engage with radiation method.

( Rate and the number is copied to others, I myself will not analyze. I feel this character and it depends on the data 

(To add random srand to increase randomness.

#include<bits/stdc++.h>
#define rep(i,a,b) for(int i=a;i<=b;i++)
using namespace std;
const int maxn=110;
const double pi=acos(-1.0);
const double inf=0x7fffffff;
struct point {
    double x,y;
    point(){}
    point(double xx,double yy):x(xx),y(yy){}
};
struct line{
    point s,p;
    line(){}
    line(point xx,point yy):s(xx),p(yy){}
};
double getdis(point w,point v){
    return sqrt((w.x-v.x)*(w.x-v.x)+(w.y-v.y)*(w.y-v.y));
}
point operator /(point a,double t){ return point(a.x/t,a.y/t);}
point operator *(point a,double t){ return point(t*a.x,t*a.y);}
point operator -(point w,point v){return point(w.x-v.x,w.y-v.y);}
point operator +(point w,point v){return point(w.x+v.x,w.y+v.y);}
double det(point w,point v){ return w.x*v.y-w.y*v.x;}
double dot(point w,point v){ return w.x*v.x+w.y*v.y;}
double ltoseg(point p,point a,point b){
    point t=p-a;
    if(dot(t,b-a)<=0) return getdis(p,a);
    else if(dot(p-b,a-b)<=0) return getdis(p,b);
    return fabs(det(t,b-a))/getdis(a,b);
}
point p[maxn],tp[maxn]; double dist[maxn]; int N; line L[maxn];
bool isinside(point a)
{
//Algorithm Description: First, the horizontal edge of the polygon are not considered, secondly,
 // for the polygon vertices and intersected by the ray, the vertex when the edge if it belongs to a larger vertex ordinate, the count is ignored otherwise points
 // Finally, in the case of polygon Q, Q directly judge whether a polygon. 
    int ncross = 0 ; 
    REP (I, 0 , N- . 1 ) { 
        Point P1 = P [I], P2 = P [I + . 1 ];
         IF (ltoseg (A, P [I], P [I + . 1 ]) = = 0 ) return  to true ; // on the line segment 
        IF (p1.y == p2.y) Continue ; // default make horizontal line x-axis, the horizontal irrespective 
        IF (AY <min (p1.y, P2. Y)) Continue ; // phase from not considered
        if(a.y>max(p1.y,p2.y)) continue;
        double t=det(a-p[i],a-p[i+1]);
        if((t>=0&&p[i].y<a.y&&p[i+1].y>=a.y)||(t<=0&&p[i+1].y<a.y&&p[i].y>=a.y)) ncross++;
    }
    return (ncross&1);
}
double getmindis(point a)
{
    double ans=inf;
    rep(i,0,N-1) ans=min(ans,ltoseg(a,p[i],p[i+1]));
    return ans;
}
int main()
{
    srand(unsigned(time(NULL)));
    while(~scanf("%d",&N)&&N){
        double X,Y,R; X=Y=0;
        rep(i,1,N) {
            scanf("%lf%lf",&p[i].x,&p[i].y);
            X=max(X,p[i].x);
            Y=max(Y,p[i].y);
        }
        p[0]=p[N];
        rep(i,0,N-1) L[i]=line(p[i],p[i+1]-p[i]);
        scanf("%lf",&R);
        int maxt=min(N,20);
        rep(i,0,maxt-1){
            tp[i]=(p[i]+p[i+1])/2;
            dist[i]=0;
        }
        double step=min(X,Y);
        const int maxd=10;
        const double rate=0.55;
        bool flag=0;
        const double EPS2=1e-6;
        while(step>EPS2&&!flag){
            rep(i,0,maxt-1){
                rep(j,0,maxd-1){
                    double d=rand()%360/360.0*2*pi;
                    point next=tp[i];
                    next.x+=step*sin(d);
                    next.y+=step*cos(d);
                    if(!isinside(next)) continue;
                    double tdis=getmindis(next);
                    if(tdis+EPS2>dist[i]){
                        dist[i]=tdis; tp[i]=next;
                    }
                    if(tdis+EPS2>=R){
                        flag=1; break;
                    }
                }
            }
            step*=rate;
        }
        if(flag) puts("Yes");
        else puts("No");
    }
    return 0;
}

 

Guess you like

Origin www.cnblogs.com/hua-dong/p/10991200.html