1.POJ1379

HDU 1109题面相同
题意:给定0——X,0——Y的矩形,给定n个点的坐标,在矩形中求得一个点是的该点到所有点的最短距离最大。(保留小数 )
分析:模拟退火(随机化)算法,可求解精度要求较小的几何寻点问题.
随机选取多个(20个)初始点,进行多次随机坐标变换,并且根据降温概率进行选择是否转移次优解。
随机坐标变换:随机半径,随机角度进行改变坐标.

#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<ctime>

using namespace std;
typedef double db;
const int maxn=1e3+10;
const int maxm=20;
const db PI=acos(-1.0);
db X,Y;
int n;
db dis[100];

struct point{
    db x,y;
    point(){}
    point( db _x,db _y ):x(_x),y(_y){ }
    point operator - ( point p ) { return point(x-p.x,y-p.y) ; }
    db dis() { return sqrt(x*x+y*y); }
}a[maxn],ans[maxn];

db getMinDis( point p )
{
    double res=1e9;
    for( int i=0;i<n;i++ ) res=min(res,(p-a[i]).dis() );
    return res;
}

point SA()
{
    for( int i=0;i<maxm;i++ )
    {
        ans[i].x=( rand()%1000+1 )/1000.0*X;
        ans[i].y=( rand()%1000+1 )/1000.0*Y;
        dis[i]=getMinDis(ans[i]);        
    }
    db delta=max(X,Y)/sqrt(n*1.0),d=0.9;
    while( delta>0.01 )
    {
        for( int i=0;i<maxm;i++ )
        {
            for( int j=0;j<maxm;j++ )
            {
                point t=ans[i];
                db angle=rand()%1000/1000.0*2*PI;
                db dx=delta*cos(angle)*(rand()%1000/1000.0);
                db dy=delta*sin(angle)*(rand()%1000/1000.0);
                t.x+=dx;t.y+=dy;
                if( t.x<0 || t.x>X || t.y<0 || t.y>Y ) continue;
                db tmp=getMinDis(t);
                db delta2=tmp-dis[i];
                if( delta2>0 ) dis[i]=tmp,ans[i]=t;
                else if( tmp>dis[i] && exp( -delta2/delta )*RAND_MAX>rand() );
                else t.x-=dx,t.y-=dy;
            }
        }
        delta*=d;
    }
    db dd=0;int pp=0;
    for( int i=0;i<maxm;i++ )
    {
        if( dis[i]>dd ) dd=dis[i],pp=i;
    }
    return ans[pp];
}

int main()
{
    srand(time(0));
    int T;
    scanf("%d",&T);
    while( T-- )
    {
        scanf("%lf%lf%d",&X,&Y,&n);
        for( int i=0;i<n;i++ ) scanf("%lf%lf",&a[i].x,&a[i].y);
        point p=SA();
        printf("The safest point is (%.1f, %.1f).\n", p.x, p.y);
    }
}

2.POJ 2420

题意:给定n个点的坐标,求是否存在一点到n个点的距离之和最小.输出最小距离之和.(n<=100,0<=xi、yi<=1000 )
分析:该点一定是在n个点环绕的封闭区域中,这道题我们只用取横纵坐标的最大最小值来限制随机点的坐标,然后根据模拟退火进行随机搜索.
注:这道题是多组读入,降温系数d不可太大容易TLE.

#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<ctime>

using namespace std;
typedef double db;
const int maxn=1e3+10;
const int maxm=30;
const db PI=acos(-1.0);
db X,Y,X1,Y1;
int n;
db dis[100];

struct point{
    db x,y;
    point(){}
    point( db _x,db _y ):x(_x),y(_y){ }
    point operator - ( point p ) { return point(x-p.x,y-p.y) ; }
    db dis() { return sqrt(x*x+y*y); }
}a[maxn],ans[maxn];

db getMinDis( point p )
{
    double res=0;
    for( int i=0;i<n;i++ ) res+=(p-a[i]).dis();
    return res;
}

db SA()
{
    for( int i=0;i<maxm;i++ )
    {
        ans[i].x=( rand()%1000+1 )/1000.0*X;
        ans[i].y=( rand()%1000+1 )/1000.0*Y;
        dis[i]=getMinDis(ans[i]);        
    }
    db delta=max(X-X1,Y-Y1),d=0.5;
    while( delta>0.01 )
    {
        for( int i=0;i<maxm;i++ )
        {
            for( int j=0;j<maxm;j++ )
            {
                point t=ans[i];
                db angle=rand()%1000/1000.0*2*PI;
                db dx=delta*cos(angle)*(rand()%1000/1000.0);
                db dy=delta*sin(angle)*(rand()%1000/1000.0);
                t.x+=dx;t.y+=dy;
                if( t.x<X1 || t.x>X || t.y<Y1 || t.y>Y ) continue;
                db tmp=getMinDis(t);
                db delta2=tmp-dis[i];
                if( delta2<0 ) dis[i]=tmp,ans[i]=t;
                else if( tmp>dis[i] && exp( -delta2/delta )*RAND_MAX>rand() );
                else t.x-=dx,t.y-=dy;
            }
        }
        delta*=d;
    }
    db res=1e12;
    for( int i=0;i<maxm;i++ ) res=min(res,dis[i]);
    return res;
}

int main()
{
    srand(time(0));

    while( ~scanf("%d",&n) )
    {
                X1=1e9,Y1=1e9;
        for( int i=0;i<n;i++ ) 
        {
            scanf("%lf%lf",&a[i].x,&a[i].y);
            X=max(X,a[i].x);Y=max(Y,a[i].y);
            X1=min(X1,a[i].x);Y1=min(Y1,a[i].y);
        }
        printf("%.0lf\n",SA());
    }
}

3.POJ3466

题意:给定n个顶点围成的多边形,求在多边形内部是否能放下半径为x的圆.

#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <algorithm>

using namespace std;

const int maxn = 100;
const double eps = 1e-3;
const int times = 5;
const double INF = 99999999;

int n;

struct point
{
    double x, y, r;
} p[maxn], test[maxn];

inline int dblcmp( double x )
{
    if( fabs(x) < eps )
        return 0;
    return x > 0 ? 1 : -1;
}

inline double sqr( double x )
{
    return x*x;
}

double dis( point& aa, point& bb )
{
    return sqrt(sqr(aa.x-bb.x)+sqr(aa.y-bb.y));
}

double cross( point& k, point& aa, point& bb )
{
    return (k.x-aa.x)*(k.y-bb.y)-(k.y-aa.y)*(k.x-bb.x);
}

//线段到点的距离
double seg_point_dis( point& l1, point& l2, point& k )
{
    double a, b, c;
    a = dis(l1, k);
    b = dis(l2, k);
    c = dis(l1, l2);

    //这里的判断是由余弦定理推出来的
    if( dblcmp(a*a+c*c-b*b) < 0 )
        return a;
    else if( dblcmp(b*b+c*c-a*a) < 0 )
        return b;
    else
        return fabs(cross(k, l1, l2)/c);
}

//判断点是否在多边形内
//思想:过点p做一条射线,判断交点数
bool point_inside( point& aa )
{
    int i, cnt = 0;
    double t;

    //确保p[n] = p[0]
    for( i = 0; i < n; ++i )
    {
        if( (p[i].y <= aa.y && p[i+1].y > aa.y) ||
            (p[i+1].y <= aa.y && p[i].y > aa.y) )
        {
            if( !dblcmp(p[i].y-p[i+1].y) )
            {
                if( dblcmp(p[i].y-aa.y) == 0 )
                    cnt++;
                t = -INF;
            }
            else
                t = p[i+1].x - (p[i+1].x-p[i].x)*(p[i+1].y-aa.y)/(p[i+1].y-p[i].y);

            if( dblcmp( t - aa.x ) >= 0 )
                cnt++;
        }
    }

    return cnt%2;
}

void cal( point& aa )
{
    double t;
    aa.r = INF;
    for( int i = 0; i < n; ++i )
    {
        t = seg_point_dis(p[i], p[i+1], aa);
        aa.r = min(aa.r, t);
    }
}

int main()
{
    int i, j;
    double R, delte, maxx, maxy, minx, miny, ang;
    point temp;
    bool ok;

    while( scanf("%d", &n), n )
    {
        ok = 0;
        maxx = maxy = 0;
        minx = miny = INF;
        for( i = 0; i < n; ++i )
        {
            scanf("%lf %lf", &p[i].x, &p[i].y);
            maxx = max(maxx, p[i].x);
            maxy = max(maxy, p[i].y);
            minx = min(minx, p[i].x);
            miny = min(miny, p[i].y);
        }
        p[n] = p[0];
        for( i = 0; i < n; ++i )
        {
            test[i].x = (p[i].x+p[i+1].x)/2;
            test[i].y = (p[i].y+p[i+1].y)/2;
            test[i].r = 0;
        }
        scanf("%lf", &R);

        maxx -= minx;    maxy -= miny;
        delte = sqrt(maxx*maxx+maxy*maxy)/2;
        while( !ok && delte > eps )
        {
            for( i = 0; !ok && i < n; ++i )
            {
                for( j = 0; !ok && j < times; ++j )
                {
                    ang = rand();
                    temp.x = test[i].x + delte*cos(ang);
                    temp.y = test[i].y + delte*sin(ang);
                    if( point_inside(temp) )
                    {
                        cal(temp);
                        if( temp.r > test[i].r )
                        {
                            test[i] = temp;
                            if( dblcmp(temp.r-R) >= 0 )
                                ok = 1;
                        }
                    }
                }
            }
            delte *= 0.90;
        }

        if( ok )
            printf("Yes\n");
        else
            printf("No\n");
    }

    return 0;
}

https://www.cnblogs.com/kuangbin/p/3267599.html

搁着,暂时补不动....