题目大意:
在一个给定长宽的矩形中,已知有n个地雷,现在要求出矩形内一个点,使该点到其最近的地雷的距离最远,且没有其他点到其最近地雷的距离会比该点的大。
解析:
此题按照"pku_3285 Point of view in Flatland"讲的那样模拟退火,只是因为可能会出现在地雷成堆聚集,然后几个堆有相隔很远的情况,这样单一退火很容易导致WA,所以采用多组初始解并行退火,最后求这几组解的最优解。
源代码如下:(来自duolon)
#include <cstdio>
#include <cmath>
#include <ctime>
#include <cstdlib>
#include <algorithm>
using namespace std;
const int N = 1050;
const int M = 30;
const int L = 30;
const double eps = 1e-3;
struct Point
{
double x, y, d;
};
Point p[N];
int n;
int X, Y;
Point s[M];
double sqr(double x)
{
return x * x;
}
double dis(int idx)
{
if (s[idx].x < 0 || s[idx].x > X) return 0;
if (s[idx].y < 0 || s[idx].y > Y) return 0;
double ret = 1e10;
for (int i = 1; i <= n; i++)
ret = min(ret, sqr(s[idx].x - p[i].x) + sqr(s[idx].y - p[i].y));
return ret;
}
void work()
{
scanf("%d%d%d", &X, &Y, &n);
for (int i = 1; i <= n; i++)
scanf("%lf%lf", &p[i].x, &p[i].y);
for (int i = 1; i < M; i++)
{
s[i].x = rand() % (X+1);
s[i].y = rand() % (Y+1);
s[i].d = dis(i);
}
for (double delta = max(X, Y); delta > eps; delta *= 0.88)
for (int i = 1; i < M; i++)
for (int j = 1; j <= L; j++)
{
double phi = rand();
s[0].x = s[i].x + delta * cos(phi);
s[0].y = s[i].y + delta * sin(phi);
if ((s[0].d = dis(0)) > s[i].d)
s[i] = s[0];
}
int idx = 1;
for (int i = 1; i < M; i++)
if (s[i].d > s[idx].d)
idx = i;
printf("The safest point is (%.1f, %.1f).\n", s[idx].x, s[idx].y);
}
int main()
{
int T;
scanf("%d", &T);
while (T--)
work();
}
注意:
1、srand(time(NULL)); 不能用这个来初始化随机种子,pku上禁止time(NULL),会返回runtime error。若要用srand,则srand(100)这样随便写个int进去就可以。
2、vs c++里的rand()返回 [0,2^16)的整数;gcc里rand()返回 [0,2^32)的整数。
要获得[0,1)的实数,必须写 rand() / RAND_MAX,其中RAND_MAX是定义在cstdlib头文件里的一个返回最大随机值的常量。
3、标准规定,浮点输出全都要用%f,如果是%lf 则会WA~~呃,需要提醒的是,double输入是%lf,输出是%f ;float则都是%f 。