【洛谷 P1337】[JSOI2004]平衡点 / 吊打XXX

题目链接

正解就算了吧,谁叫我理生化 语数外 政史地都菜呢

模拟退火真玄学,不知道发生了什么就跑出答案了,原理就算了吧,能用(pianfen)就好。
当重物平衡时,势能一定是最小的,于是当我随机出一个点时,累加所有重物到这个点的距离乘这个重物的质量的积,这样就能反映势能的相对大小了。
为什么不用考虑方向?自己脑补脑补就好了,反正平衡时这个东西也一定最小。
然后就是跑看脸的\(SA\)了,这个八位质数真神奇,交了很多遍都没过,一交这个就过了。

#include <cstdio>
#include <cmath>
#include <ctime>
#include <cstdlib>
const double cut = 0.993;
const double eps = 1e-14;
const int MAXN = 1010;
int n, x[MAXN], y[MAXN], w[MAXN];
double xx, yy, nowx, nowy, Ans = 1e18;
double get_E(double X, double Y){
    double ans = 0;
    for(int i = 1; i <= n; ++i){
       xx = X - x[i]; yy = Y - y[i];
       ans += sqrt(xx * xx + yy * yy) * w[i];
    }
    return ans;
}
void SA(){
    double T = 1926;
    double nx = nowx, ny = nowy;
    while(T > eps){
      double X = nx + ((rand() << 1) - RAND_MAX) * T;
      double Y = ny + ((rand() << 1) - RAND_MAX) * T;
      double ans = get_E(X, Y);
      double delta = ans - Ans;
      if(delta < 0){
        nx = X; ny = Y;
        nowx = X; nowy = Y;
        Ans = ans;
      }
      else if(exp(-delta / T) * RAND_MAX > rand()) nx = X, ny = Y;
      T *= cut;
    }
}
int sx, sy;
int main(){
    srand(19260817); srand(rand()); srand(rand());
    scanf("%d", &n);
    for(int i = 1; i <= n; ++i)
       scanf("%d%d%d", &x[i], &y[i], &w[i]), sx += x[i], sy += y[i];
    nowx = sx * 1.0 / n; nowy = sy * 1.0 / n;
    while(clock() < 800) SA();
    printf("%.3lf %.3lf%", nowx, nowy);
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/Qihoo360/p/9718320.html
今日推荐