BZOJ-1844/2210 | | POJ-1379 Run Away

[文章目录]

Description

题目看不懂,看sample懂了。就是给你一个X*Y的网格图,X,Y<=10000,然后给你m个点,m<=1000,问你与m个点的欧几里得距离的最小值最大的点的坐标。多组数据T<=10。

随机化,想平面上随机撒点,然后每个点进行爬山算法,将步长由大趋近于0。看步长可及的解是否比原解更优,如果优于原解则更新出发点。当步长趋于0时,解稳定在一个范围里。进行多次随机。更新最后的解。

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
int T,X,Y,m;
double mi,ansx,ansy,ans;
struct node
{
    int x,y;
}a[1100];
double dis(double x,double y,int id)
{
    return (x-a[id].x)*(x-a[id].x)+(y-a[id].y)*(y-a[id].y);
}
double lim(double x,double y)//更新原解
{
    if(x>X||y>Y||x<0||y<0) return 0.0;
    double re=100000000.0;
    for(int i=1;i<=m;i++)
    {
        double tmp=dis(x,y,i);
        if(tmp<re) re=tmp;
    }
    return re;
}
void check(double d,double &x,double &y)
{
    double temp=lim(x+d,y+d),tmp,tx=x+d,ty=y+d;
    tmp=lim(x-d,y+d); if(tmp>temp) temp=tmp,tx=x-d,ty=y+d;
    tmp=lim(x-d,y-d); if(tmp>temp) temp=tmp,tx=x-d,ty=y-d;
    tmp=lim(x+d,y-d); if(tmp>temp) temp=tmp,tx=x+d,ty=y-d;
    if(temp>mi) mi=temp,x=tx,y=ty;
}
int main()
{
    scanf("%d",&T);
    while(T--)
    {
        ans=mi=0;
        scanf("%d%d%d",&X,&Y,&m);
        for(int i=1;i<=m;i++)
            scanf("%d%d",&a[i].x,&a[i].y);
        int t=100000/m;
        while(t--)
        {
            double tmp=1.0*(X+Y);
            double x=rand()%X+1.0,y=rand()%Y+1.0;
            while(tmp>=1e-4)
            {
                check(tmp,x,y);
                tmp*=0.5;//将步长减小
            }
            if(mi>ans) ans=mi,ansx=x,ansy=y;
        }
        printf("The safest point is (%.1lf, %.1lf).\n",ansx,ansy);
    }
    return 0;
}

发表评论

邮箱地址不会被公开。 必填项已用*标注