题目: LINK
思想: http://www.cnblogs.com/heaad/archive/2010/12/20/1911614.html
题意:二维坐标上给出n个点的坐标,每个位置到这n个点有一个距离和,求这个距离和最小是多少。直接模拟退火搜索。 找到随机的范围,先随机出来P个点,对于每个点往周围走D步,形成L个点,找到最优的点替代P里面的点,D值缩小,达到精度即可。
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <iostream>
#include <string>
#include <vector>
#include <ctime>
#include <cmath>
#include <queue>
#include <map>
#include <set>
using namespace std;
#define INF 1000000000
//typedef __int64 LL;
#define N 111
const double pi = acos(-1.0);
const double eps = 0.01;
int n;
struct point {
double x, y;
};
point in[N], p[N], pp[N], mi, ma;
int P, L;
int Rand(int x, int y) {
int dif = y - x + 1;
return rand()%dif + x;
}
double dis(point a, point b) {
return sqrt((a.x - b.x) * (a.x - b.x) + (a.y - b.y) * (a.y - b.y));
}
double gao(point a) {
double ret = 0;
for(int i = 1; i <= n; i++) {
ret += dis(a, in[i]);
}
return ret;
}
double sol() {
for(int i = 1; i <= P; i++) {
p[i].x = Rand(mi.x, ma.x);
p[i].y = Rand(mi.y, ma.y);
}
double D = dis(mi, ma);
while(D >= eps) {
for(int i = 1; i <= P; i++) {
double mi = INF;
int mark = -1;
for(int j = 1; j <= L; j++) {
double angle = (2.0 * pi * Rand(0, 1000) / 1000);
double adx = D * cos(angle);
double ady = D * sin(angle);
pp[j].x = p[i].x + adx;
pp[j].y = p[i].y + ady;
double tmp = gao(pp[j]);
if(mi > tmp) {
mi = tmp; mark = j;
}
}
p[i] = pp[mark];
}
D *= 0.8;
}
double mi = INF;
for(int i = 1; i <= P; i++) {
mi = min(mi, gao(p[i]));
}
return mi;
}
int main() {
while(scanf("%d", &n) != EOF) {
mi.x = mi.y = INF;
ma.x = ma.y = -INF;
P = 30; L = 30;
for(int i = 1; i <= n; i++) {
scanf("%lf%lf", &in[i].x, &in[i].y);
mi.x = min(mi.x, in[i].x); mi.y = min(mi.y, in[i].y);
ma.x = max(ma.x, in[i].x); ma.y = max(ma.y, in[i].y);
}
double ans = sol() ;
printf("%.0lf\n", ans);
}
return 0;
}