洛谷 P1337 [JSOI2004]平衡点 / 吊打XXX 解题报告

P1337 [JSOI2004]平衡点 / 吊打XXX

题目描述

\(n\) 个重物,每个重物系在一条足够长的绳子上。每条绳子自上而下穿过桌面上的洞,然后系在一起。\(X\)处就是公共的绳结。假设绳子是完全弹性的(不会造成能量损失),桌子足够高(因而重物不会垂到地上),且忽略所有的摩擦。

问绳结 \(X\) 最终平衡于何处。

注意:桌面上的洞都比绳结 \(X\) 小得多,所以即使某个重物特别重,绳结 \(X\) 也不可能穿过桌面上的洞掉下来,最多是卡在某个洞口处。

输入输出格式

输入格式:

文件的第一行为一个正整数\(n(1≤n≤1000)\),表示重物和洞的数目。

接下来的 \(n\) 行,每行是3个整数:\(X_i,Y_i,W_i\),分别表示第\(i\)个洞的坐标以及第\(i\)个重物的重量。\((-10000≤x,y≤10000, 0<w≤1000)\)

输出格式:

你的程序必须输出两个浮点数(保留小数点后三位),分别表示处于最终平衡状态时绳结 \(X\) 的横坐标和纵坐标。两个数以一个空格隔开。


搞一个位置,然后模拟退火

注意一下

关于随机移动位置的相对大小,和温度相关

跳出去的概率为\(e^{\frac{-\Delta E}{T}}>k\),\(k\)\((0,1)\)之间随机的


Code:

#include <cstdio>
#include <ctime>
#include <cmath>
#include <cstdlib>
const int N=1010;
double dx[N],dy[N],w[N];
int n;
double cal(double x,double y)
{
    double ret=0;
    for(int i=1;i<=n;i++) ret+=sqrt((dx[i]-x)*(dx[i]-x)+(dy[i]-y)*(dy[i]-y))*w[i];
    return ret;
}
double ans,ansx,ansy,delta=0.997;
void SA()
{
    double T=2333;
    while(T>1e-12)
    {
        double tx=ansx+(rand()*2-RAND_MAX)*T;
        double ty=ansy+(rand()*2-RAND_MAX)*T;
        double E=cal(tx,ty);
        if(E<ans) ansx=tx,ansy=ty,ans=E;
        else if(exp((ans-E)/T)*RAND_MAX>rand()) ansx=tx,ansy=ty;
        T*=delta;
    }
}
int main()
{
    srand(time(0)^2333333^998244854);
    scanf("%d",&n);
    for(int i=1;i<=n;i++) scanf("%lf%lf%lf",dx+i,dy+i,w+i),ansx+=dx[i],ansy+=dy[i];
    ansx=ansx/n,ansy=ansy/n,ans=cal(ansx,ansy);
    SA(),SA(),SA(),SA(),SA(),SA(),SA(),SA();
    printf("%.3lf %.3lf\n",ansx,ansy);
    return 0;
}

2019.2.17

posted @ 2019-02-17 14:34  露迭月  阅读(287)  评论(0编辑  收藏  举报