BZOJ 3680 吊打XXX 计算几何 模拟退火 广义费马点

题目大意:有个人(gty)被吊打,他机智的使用了分身,但是每个分身有他的重力,把这些gty的分身绑起来,经过一个公共的绳结,求这个绳结最后在哪里。

思路:其实这个题就转化成了:定义一个点到一个分身的距离是两点间的距离 * 分身的重力。求平面内到这些点的距离的和的最小值。和poj2420差不多,这个题只需要在统计的时候吧权值乘上每个分身的重量就可以了。

值得一提的是这个题要求精度到1e-3,写的时候还是有点怕的,但是其实精度把握的合适还是能切这个题的。

一开始MAX开了10000,怎么改参数都是挂。。血的教训啊。。。


CODE:


#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define MAX 10010
#define INF 1e17
#define EPS 1e-3
#define PI acos(-1.0)
using namespace std;
 
struct Point{
    double x,y;
    double weight;
    double total_weight;
     
    Point(double _x,double _y):x(_x),y(_y) {}
    Point() {}
    void Read() {
        scanf("%lf%lf%lf",&x,&y,&weight);
    }
}point[MAX],now,ans;
 
int points;
 
inline double Calc(Point p1,Point p2);
inline double Statistic(Point p);
inline double Rand();
void SinulatedAnnealing();
 
int main()
{
    srand(19980531);
    cin >> points;
    for(int i = 1;i <= points; ++i) {
        point[i].Read();
        now.x += point[i].x;
        now.y += point[i].y;
    }
    now.x /= points,now.y /= points;
    ans.total_weight = INF;
    SinulatedAnnealing();
    printf("%.3lf %.3lf\n",ans.x,ans.y);
    return 0;
}
 
inline double Calc(Point p1,Point p2)
{
    return sqrt((p1.x - p2.x) * (p1.x - p2.x) + 
                (p1.y - p2.y) * (p1.y - p2.y));
}
 
inline double Statistic(Point p)
{
    double re = 0.0;
    for(int i = 1;i <= points; ++i)
        re += Calc(p,point[i]) * point[i].weight;
    if(re < ans.total_weight)
        ans = p,ans.total_weight = re;
    return re;
}
 
void SinulatedAnnealing()
{
    double T = 100000.0;
    while(T > EPS) {
        double alpha = 2.0 * PI * Rand();
        Point temp(now.x + T * cos(alpha),now.y + T * sin(alpha));
        double dE = Statistic(now) - Statistic(temp);
        if(dE >= 0 || exp(dE / T) >= Rand())
            now = temp;
        T *= .99;
    }   
    T = .001;
    for(int i = 1;i <= 1000; ++i) {
        double alpha = 2.0 * PI * Rand();
        Point temp(ans.x + T * cos(alpha) * Rand(),ans.y + T * sin(alpha) * Rand());
        Statistic(temp);
    }
}
 
inline double Rand()
{
    return (rand() % 1000 + 1) / 1000.0;
}


你可能感兴趣的:(计算几何,模拟退火,bzoj,BZOJ3680,广义费马点)