洛谷 SP34 RUNAWAY - Run Away
SP34 RUNAWAY - Run Away
这道题和那道平衡点吊打XXX有点像。
不同的是那道题中的每个点都有权值,而这道题没有,然后求的东西也不太一样,不过万变不离其宗,还是可以用模拟退火做。
而且这道题的数据比较弱,所以随便调参基本都可以过,不像其他题目的参数极度看脸, 是一道对欧洲人与非洲人都十分友好的模拟退火入坑题。
具体步骤见下面代码注释:
Code:
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
using namespace std;
//Mystery_Sky
//
#define M 1000100
#define INF 0x3f3f3f3f
struct node{
int x, y;
}point[M];
int t, n, X, Y;
const double delta = 0.993;//降温系数
double ans_x, ans_y;
inline double dist(double x, double y)//求出题中要求的距离所有点的最小值
{
double maxx = INF;
for(int i = 1; i <= n; i++) {
double dx = point[i].x - x;
double dy = point[i].y - y;
double dis = sqrt(dx * dx + dy * dy);
maxx = min(dis, maxx);
}
return maxx;
}
inline void SA()
{
double x = ans_x, y = ans_y;
double T = 2000;//初始温度。
double Ans = 0;
while(T > 1e-14) {
double new_x = x + ((rand()<<1) - RAND_MAX) * T;
double new_y = y + ((rand()<<1) - RAND_MAX) * T;
if(new_x > X || new_y > Y || new_x < 0 || new_y < 0) {//若随机出的新答案不在题目约束的范围内,则跳过后续部分,重新生成新解。
T *= delta;
continue;
}
double new_ans = dist(new_x, new_y);
double DE = Ans - new_ans;
if(DE < 0) {//如果生成的新答案比之前得到的最优解更大,则接受这个新答案。
ans_x = x = new_x;
ans_y = y = new_y;
Ans = new_ans;
}
else if(exp(-DE/T) * RAND_MAX > rand()) x = new_x, y = new_y;//否则以一定的概率接受这个新答案(模拟退火不同于爬山算法之处)。
T *= delta;//降温。
}
}
int main() {
srand(19260817);
srand(rand());
srand(rand());//玄学种子
scanf("%d", &t);
while(t--) {
int sum_x = 0;
int sum_y = 0;
scanf("%d%d%d", &X, &Y, &n);
for(int i = 1; i <= n; i++) {
scanf("%d%d", &point[i].x, &point[i].y);
sum_x += point[i].x;
sum_y += point[i].y;
}
ans_x = (double)sum_x / n;
ans_y = (double)sum_y / n;//沿用平衡点吊打XXX那道题的做法,继续使用所有点的平均值的点作为初始的答案。
SA();
SA();
SA();
printf("The safest point is (%.1lf, %.1lf).\n", ans_x, ans_y);
}
return 0;
}
唯愿,青春不辜负梦想,未来星辰闪耀