看着超哥的代码打的...
觉得爬山和退火算法挺神奇的,这都能搞出结果了
题意: 给出三维空间n个点,求出到这n个点的距离之和最小的一个点
虽然不知道为什么是单峰的,但是想想还是觉得有道理
设s(i)为状态i到所有点的距离
爬山就是应付单峰函数的,从状态x开始爬,假设爬到y,如果s(y)<s(x),就把当前状态更新为y
枚举完一个点所能到的所有点,再缩小爬的距离
http://www.cnblogs.com/heaad/archive/2010/12/20/1911614.html
这里讲的真心好
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<set>
#include<map>
#include<queue>
#include<vector>
#include<cstdlib>
#include<stack>
using namespace std;
#define inf 0x3f3f3f3f
#define eps 1e-8
#define LL long long
#define ULL unsigned long long
#define MP make_pair
#define pb push_back
#define ls i << 1
#define rs ls | 1
#define md ( ( ll[i] + rr[i] ) >> 1 )
#define mxn 100020
struct point {
double x, y, z;
point() {}
point( double x, double y, double z ): x( x ), y( y ), z( z ) {}
void input() {
scanf( "%lf%lf%lf", &x, &y, &z );
}
point operator - ( const point &b ) const {
return point( x - b.x, y - b.y, z - b.z );
}
double len() {
return sqrt( x * x + y * y + z * z );
}
}p[mxn];
int n;
int dx[30], dy[30], dz[30];
int tot = 0;
double calc( point cur ) {
double ret = 0;
for( int i = 0; i < n; ++i )
ret += ( p[i] - cur ).len();
return ret;
}
void solve() {
point cur = point( 0, 0, 0 );
double dlt = 0;
for( int i = 0; i < n; ++i )
dlt = max( dlt, ( p[i] - cur ).len() );
while( dlt > eps ) { // 每次爬的距离
point pre = cur;
double k = calc( cur );
for( int i = 0; i < tot; ++i ) { // 枚举爬的各个方向
point nxt = point( pre.x + dx[i] * dlt, pre.y + dy[i] * dlt, pre.z + dz[i] * dlt );
double kk = calc( nxt );
if( kk < k ) { //到达新的状态的总距离比当前的总距离小
cur = nxt;
k = kk;
}
}
dlt *= 0.992; // 缩小爬的距离
}
printf( "%.3lf %.3lf %.3lf\n", cur.x, cur.y, cur.z );
}
int main() {
for( int i = -1; i <= 1; ++i )
for( int j = -1; j <= 1; ++j )
for( int k = -1; k <= 1; ++k )
dx[tot] = i, dy[tot] = j, dz[tot++] = k;
while( scanf( "%d", &n ) != EOF ) {
for( int i = 0; i < n; ++i )
p[i].input();
solve();
}
return 0;
}