模拟退火算法,其实不如说随机化变步长的贪心,向四周搜索,如果碰到更小的则把它作为更优解。
本题代码中费马点部分可作为模版使用。
#include <iostream> #include <stdio.h> #include <math.h> #define MAX_NUM 128 struct point { double x; double y; }; double distance(point p1, point p2){ return sqrt((p1.x - p2.x)*(p1.x - p2.x) + (p1.y - p2.y)*(p1.y - p2.y)); } //多边形费马点,点集pt,大小n,传入ptres作为费马点这一点,返回值是所有点到费马点的距离 double fermat_point(point pt [], int n, point & ptres) { point u, v; double step = 0.0, curlen, explen, minlen; int i, j, k, idx; bool flag; u.x = u.y = v.x = v.y = 0.0; for (i = 0; i < n; ++i) { step += fabs(pt[i].x) + fabs(pt[i].y); u.x += pt[i].x; u.y += pt[i].y; } u.x /= n; u.y /= n; flag = 0; while (step > 1e-10) { for (k = 0; k < 10; step /= 2, ++k) for (i = -1; i <= 1; ++i) for (j = -1; j <= 1; ++j) { v.x = u.x + step*i; v.y = u.y + step*j; curlen = explen = 0.0; for (idx = 0; idx < n; ++idx) { curlen += distance(u, pt[idx]); explen += distance(v, pt[idx]); } if (curlen > explen) { u = v; minlen = explen; flag = 1; } } } ptres = u; return flag ? minlen : curlen; } int main() { //freopen("in.txt", "r", stdin); //freopen("out.txt", "w", stdout); int n, i; double res; point pt[MAX_NUM], ptres; while (std::cin>>n) { for (i = 0; i < n; ++i) { std::cin>>pt[i].x>>pt[i].y; } res = fermat_point(pt, n, ptres); //std::cout << ptres.x << ' ' << ptres.y << std::endl; if (res - (int) (res) > 0.5) printf("%d\n", (int) (res + 1)); else printf("%d\n", (int) (res)); } }