シミュレーテッドアニーリング - 本当の喜び(絶望

数日前気まぐれ、それ語学教室を活用してください(私は「ロス・スーパーグータスクリスト」を見つけることができないので、ガン!ない$ JS $スクリプト$ LIN $の$ _のTOTOの$)タスクリストに従事脳、その後、醤油、置くシミュレーテッドアニーリング Gonggongzhengzhengを私は南のだけど、アップ書き込み、長い時間のための科学は、外国のビデオの多くが理解することができました。

小さな話題

図:YES \(N- \)重量で、十分な長さロープに基づいて、各重み。デスクトップ上の穴から上から下までの各ロープは、その後、一緒に接続します。\(X \)は結び目で共通です。ロープが(エネルギー損失が発生することはありません)完全弾性であると仮定すると、テーブルには、十分に高い(したがって、重量は地面にはない)、およびすべての摩擦を無視します。

Xは、最終的な平衡どこに結び目を尋ねました。

注:結び目よりもデスクトップ上の穴\(X \)がはるかに小さいので、でも特に重い、ノット\(X \)は、ほとんどのカードで、デスクトップ上に穴を通って落下することはできません穴インチ

入力形式

ファイル正の整数の最初の行\(N- \)\((1≤n≤1000)\) 重みと正孔の数を表します。\(N- \)行、各行は3の整数である:\(Xi.Yi.Wi \)、i番目と第一孔の座標を表す(iは\)\の重量物の重量。$( - 10000≤x、y≤10000、0 <w≤1000)$

出力フォーマット

プログラムは出力をそれぞれ2つ(小数点以下3桁の後に)浮動小数点、横軸及びXノットの最終的な平衡状態で縦なければなりません。スペースで区切られた2つの数字。

どのようなシミュレーテッドアニーリングああ

事実は、Baiduの百科事典は、愚かになります見ることを証明している\(OI \)アニーリングや分子の熱運動はあまり重要ではないん。

小さな考えて

私たちは、全国の都市の数の座標を知って、北京からのルートを求めていることは、すべての都市だけに一度行くための最短の道を通るパスを作ります

この質問は......あれば、検索語の直接の暴露である
25の都市がある場合は、あなたが(PCの\)を\ 1秒1E8回の操作よりも強い、寧約数える」働いた49億年後、それは恐ろしい、
しかしでシミュレーテッドアニーリング、すぐに答えを計算することができます。

シミュレーテッドアニーリングを求めるために使用されるマルチモーダル関数極値に速い速度で得ることができる(通常は反映されないマルチモーダル機能はむしろ彼らが望む必要があるでしょうが)のに適切なパラメータを設定する近似最適解ように、アルゴリズムは必ずしも満点ではないですが、あなたは簡単にハイスコアを取得することができます。

説明するために、この個人的な経験の上部タイトルを行うために

私はいくつかの概念についてお話しましょう

\(T \) 初期温度、回数、確率の高い正の解が、より長い時間のかかるより多くの量を設定し、自分の感情やトピックを見て、です。

\(ダウン\) ように係数を冷却の目的は、この係数が設定されている\(T \)が適切な速度に低減することができたときに、\(T \)が国境に到達したとき、我々は解決策の多くを試してみました最適解に近い最終的な解決策。指数成長率は非常に高速であるので、私たちは与えることができます(\ダウン)\を通常、小さな値に添付- (0.995 \ 0.98)\
正確な、より高速の詳細いない間、適切な場合には、いじり。

\(exp( n )\) :c++一个函数,计算\(e ^ n\),其中\(e\)为自然对数。

\(de\) : 这次得到的解和之前求到的最优解的差值,有点类似于化学里的熵变,用来评价这次的解是否更优。

\(RAND\)_ \(MAX\) (这个为什么这么大):c++能生成的最大的随机数,即32767。

\(rand()\) :c++函数,生成随机数。

怎么退火呢?

举个烂大街的栗子:

贪心算法:兔子朝着比现在高的地方跳去。它找到了不远处的最高山峰。但是这座山不一定是珠穆朗玛峰。这就是贪心,它不能保证局部最优值就是全局最优值。

模拟退火:兔子喝醉了。它随机地跳了很长时间。这期间,它可能走向高处,也可能踏入平地。但是,它渐渐清醒了并朝最高方向跳去。这就是模拟退火。

一张图骗:

可以看到它是逐渐趋近于最优解的

本题为例的伪代码:

int T = 233;
int tempx, tempy, tempans, de;
//下面的x, y, ans为临时最优解
while( T > 1e-15 ){  //T十分接近零
    tempx = x + (rand() * 2 - RAND_MAX) * T;
    tempy = y + (rand() * 2 - RAND_MAX) * T;
    //以本题为例,rand() * 2 - RAND_MAX是一个小套路,这样可以生成从 -32767 到 32767 的随机数,以让坐标点转移到一个随机位置,随着不断降温,T会越来越小,所以坐标点转移的范围也会越来越小,逐渐逼近最优点
    tempans = solve( tempx, tempy )
    //solve是你用来求距离的函数
    de = tempans - ans;
    if( de < 0 ){//是大于还是小于具体问题判断   
        x = tempx;
        y = tempy;
        w = tempw;
    } else if( exp( -de / T ) * RAND_MAX > rand() ){//以一个概率选择是否接受,但是就算是接受,我们也不会用它来更新最优解,因为我们当前的最优解比它优秀。de的正负性具体题目具体分析,也可以两个都试一下,看哪个输出正确样例   
        x = tempx;
        y = tempy;  
    }
    T *= down;//降温
}

题目分析

我最开始想的是受力分析然后搞个合力,最后物体在合力方向上移动,但是一想,合力方向似乎会变,然后就没想法了(俺太弱了\(QWQ\)
看讨论区有人说用质心公式搞???我不太懂,没搞。
最后用模拟退火瞎搞出来的,看题解还有大佬用凸包什么的搞出来了,反正我不会。

然后就模拟退火搞呗,考虑到重力势能是趋近于系统重力势能最小的,所以当绳子的结点静止时,重力势能之和最小,那么我们可以求出在每个点时的重力势能大小,以此来比较当前解和最优解。

AC代码:

#include<bits/stdc++.h>
using namespace std;
#define rint register int
#define down //请自己尝试

int de;
int n;
double ansx, ansy, answ;
struct node{
    int x, y, w;
}a[1050];

inline int read( void ){
    int re = 0, f = 1;
    char ch = getchar();
    while( ch > '9' || ch < '0' ){
        if( ch == '-' ) f = -1;
        ch = getchar();
    }
    while( ch >= '0' && ch <= '9' ){
        re = re * 10 + ch - '0';
        ch = getchar();
    }
    return re * f;
}
inline double init( double x, double y ){
    double re = 0.0, d1, d2;
    for( rint i = 1; i <= n; i++ ){
        d1 = x - a[i].x, d2 = y - a[i].y;
        re += sqrt( d1 * d1 + d2 * d2 ) * a[i].w;
    }
    return re;
}
inline void SA(){
    double T = //请自己尝试
    double de, tw, tx, ty;
    while( T > 1e-15 ){
        //cout << T << endl;
        tx = ansx + ( rand() * 2 - RAND_MAX ) * T;
        ty = ansy + ( rand() * 2 - RAND_MAX ) * T;
        tw = init( tx, ty );
        de = tw - answ;
        if( de < 0 ){
            ansx = tx;
            ansy = ty;
            answ = tw;
        } else if( exp( -de / T ) * RAND_MAX > rand() ){    
            ansx = tx;
            ansy = ty;  
        }
        T *= down;
    }
}
int main( void ){
    n = read();
    for( rint i = 1; i <= n; i++ ){
        a[i].x = read(); a[i].y = read(); a[i].w = read();
        ansx += a[i].x, ansy += a[i].y;
    }
    ansx /= n, ansy /= n;
    answ = init( ansx, ansy );
    //cout << ansx << ' ' << ansy;
    SA();
    SA();
    SA();
    SA();
    SA();
    printf( "%.3lf %.3lf", ansx, ansy );
    return 0;
}

おすすめ

転載: www.cnblogs.com/with6676/p/11695978.html