1. 程式人生 > >洛谷 P1337 [JSOI2004]平衡點 / 吊打XXX (非酋慎用的模擬退火.....慘)

洛谷 P1337 [JSOI2004]平衡點 / 吊打XXX (非酋慎用的模擬退火.....慘)

題目連結:

題目:

題目描述

如圖:有n個重物,每個重物系在一條足夠長的繩子上。每條繩子自上而下穿過桌面上的洞,然後系在一起。圖中X處就是公共的繩結。假設繩子是完全彈性的(不會造成能量損失),桌子足夠高(因而重物不會垂到地上),且忽略所有的摩擦。

問繩結X最終平衡於何處。

注意:桌面上的洞都比繩結X小得多,所以即使某個重物特別重,繩結X也不可能穿過桌面上的洞掉下來,最多是卡在某個洞口處。

輸入輸出格式

輸入格式:

檔案的第一行為一個正整數n(1≤n≤1000),表示重物和洞的數目。接下來的n行,每行是3個整數:Xi.Yi.Wi,分別表示第i個洞的座標以及第 i個重物的重量。(-10000≤x,y≤10000, 0<w≤1000 )

輸出格式:

你的程式必須輸出兩個浮點數(保留小數點後三位),分別表示處於最終平衡狀態時繩結X的橫座標和縱座標。兩個數以一個空格隔開。

輸入輸出樣例

輸入樣例#1: 複製

3
0 0 1
0 2 1
1 1 1

輸出樣例#1: 複製

0.577 1.000

說明

[JSOI]

題目大意:

中文題,略0.0

題目分析:

先放一張非酋圖鎮樓

當然了,其實沒這麼誇張,我錯了這麼多次主要是因為srand()函式種子的設定,我傳入的引數是time(NULL),這樣就不行,隨機輸入了一段數字就AC了,據我身邊的大佬LZH說,某些OJ不能用time(NULL)生成隨機數,具體原因我就不知道了,不過一定要注意,不要踩坑。

下面就開始說正事啦。

這個題,我們先想一下,這個節點什麼時候會靜止呢?我們知道,物理中,能量越低就越穩定,這兒也是一樣,總的重力勢能越低,整個體系就最穩定,那麼,我們就知道了,節點靜止的時候是最穩定的狀態,也就是說,節點靜止的時候,總的重力勢能最小

得到這個結論之後,我們再去分析一下,重力勢能都與什麼有關呢?首先,物體重量越大,重力勢能肯定越大,其次,距離節點越遠,重力勢能肯定就越大。所以每個點重力勢能就與 距離節點的距離和該點的重力 這兩個因素成對比,所以對每個點來說, 該點貢獻的重力勢能 = 係數*重量*距離節點的距離 。因為係數大家都有,就可以省略不管,然後體系的重力勢能就可以遍歷每個點然後求和

了。

得到了這個公式,之後可以怎麼做呢?求最優解0.0 哈 沒錯 就是模擬退火了 0.0(不是正解哦)

程式碼:

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstdlib>
#include <ctime>
#include <cmath>

#define random(T) (T*((rand()<<1)-RAND_MAX))

using namespace std;
const int MAXN=1000+100;
struct node{
    double x,y,w;
}a[MAXN];
const double T_MIN=1e-14;
const double DOWN=0.98;

double f(node t,int n)
{
    double ans=0;
    for(int i=0;i<n;i++)
        ans+=sqrt(pow(a[i].x-t.x,2)+pow(a[i].y-t.y,2))*a[i].w;
    return ans;
}

int main()
{
    srand(13245);
    int n;
    scanf("%d",&n);
    node s,e;
    s.x=s.y=0;
    for(int i=0;i<n;i++)
    {
        scanf("%lf %lf %lf",&a[i].x,&a[i].y,&a[i].w);
        s.x+=a[i].x;
        s.y+=a[i].y;
    }
    s.x/=n;s.y/=n;s.w=f(s,n);
    node ans=s;
    double T=100;
    while(T>T_MIN)
    {
        e.x=s.x+random(T);
        e.y=s.y+random(T);
        e.w=f(e,n);
        if(e.w<ans.w)
            ans=e;
        if(e.w<s.w||exp((s.w-e.w)/T)>(double)rand()/RAND_MAX)
            s=e;
        T*=DOWN;
    }
    printf("%.3f %.3f\n",ans.x,ans.y);
    return 0;
}