题目链接:http://poj.org/problem?id=2420
题目大意就是求二维平面中多边形的费马点,即在平面中找到一个点到多边形所有顶点的距离之和最小,并输出这个距离。
由于精度要求较低,比较容易想到模拟退火算法:在平面中选取一个初始点,然后对于八个方向开始搜索,取初始步长step后,每次搜索后选取一个最优的解作为新的起始点,然后逐渐降温,缩短步长,直至达到题目所要求的精度范围。
#include <cmath>
#include <cstdio>
using namespace std;
const double D = 20;
const double EPS = 1e-1;
struct Point {
double x, y;
Point(double x = 0, double y = 0) : x(x), y(y) { }
}p[105], pg;
double dis(const Point &p1, const Point &p2) {
return sqrt((p1.x - p2.x) * (p1.x - p2.x) + (p1.y - p2.y) * (p1.y - p2.y));
}
int gox[] = {1, -1, 0, 0, 1, 1, -1, -1};
int goy[] = {0, 0, 1, -1, 1, -1, 1, -1};
int main() {
int n;
scanf("%d", &n);
for (int i = 1; i <= n; i++) {
scanf("%lf %lf", &p[i].x, &p[i].y);
}
double ansdis = 0;
double step = 100, speed = 0.9;
pg = Point(100, 100);
for (int i = 1; i <= n; i++) ansdis += dis(p[i], pg);
while (step > EPS) {
for (int i = 1; i <= D; i++) {
for (int j = 0; j <= 7; j++) {
Point pt;
pt.x = pg.x + gox[j] * step;
pt.y = pg.y + goy[j] * step;
double tmpdis = 0;
for (int k = 1; k <= n; k++) tmpdis += dis(p[k], pt);
if (tmpdis < ansdis) {
ansdis = tmpdis;
pg = pt;
}
}
}
step *= speed;
}
printf("%.0f\n", ansdis);
return 0;
}