模拟退火 BZOJ-2428

来源:互联网 发布:表情包软件下载 编辑:程序博客网 时间:2024/06/16 02:51

大家都很强,可与之共勉。

Link

题解
首先随机设定每个元素所在的组,然后求出初始的方差,然后开始退火,每次退火时首先随机选一个元素t,并得到它所在的组x,然后需要选一组y,把t放入组y中,选这个组y也要讲究技巧,若温度高的话,此时状态不稳定,很难使最终的搜索结果尽量更优,那么就需要贪心地选当前元素值之和最小的组。若温度低的话,此时状态比较稳定,而且各个组的元素和基本上差不多,此时就需要随机选个y,然后尝试将t放入组y中,若新解更优,则把旧解更新为新解,否则在[0,10000)随机一个数,若随机的数比T小,那么就把旧解更新为新解(T越小,在这种情况下更新解的概率也就越小,T的大小相当于是解的可靠性,T越小,说明此时解越可靠,在新解并不优的情况下改变原有解的概率也就越小),否则保持原有的解不变。

真-模拟退火

/**************************************************************    Problem: 2428    User: Lazer2001    Language: C++    Result: Accepted    Time:6396 ms    Memory:1304 kb****************************************************************/# include <bits/stdc++.h>int n, m ;double ave, sum [25] ;int place [25], a [25] ;inline double smin ( double& d, const double& x )  {    x < d ? d = x : 0 ;}inline double SA ( )  {    double ans ( 0 ) ;    for ( int i = 1 ; i <= n ; ++ i )   place [i] = rand ( ) % m + 1 ;    for ( int i = 1 ; i <= m ; ++ i )   sum [i] = 0 ;    for ( int i = 1 ; i <= n ; ++ i )   sum [place [i]] += a [i] ;    for ( int i = 1 ; i <= m ; ++ i )   ans += ( sum [i] - ave ) * ( sum [i] - ave ) ;    register double temprature = 10000.0 ;    while ( temprature > 1e-8 )  {        temprature *= 0.98 ;        int t ( rand ( ) % n + 1 ), x ( place [t] ), y ;        if ( temprature > 500 )  {            y = std :: min_element ( sum + 1, sum + 1 + m ) - sum ;        }  else  {            y = rand ( ) % m + 1 ;        }        if ( x ^ y )  {            double tmp ( ans ) ;            tmp -= ( sum [x] - ave ) * ( sum [x] - ave ) ;            tmp -= ( sum [y] - ave ) * ( sum [y] - ave ) ;            sum [x] -= a [t], sum [y] += a [t] ;            tmp += ( sum [x] - ave ) * ( sum [x] - ave ) ;            tmp += ( sum [y] - ave ) * ( sum [y] - ave ) ;            if ( tmp <= ans )  {                ans = tmp ;                place [t] = y ;                continue ;            }            if ( ( rand ( ) % 1000 ) > temprature )  {                sum [x] += a [t], sum [y] -= a [t] ;            }  else  {                ans = tmp ;                place [t] = y ;            }        }    }    return ans ;} int main ( )  {    srand ( 20010608 ) ;    scanf ( "%d%d", & n, & m ) ;    sum [0] = 0x3f3f3f3f ;    double ans ( 0x3f3f3f3f ) ;    for ( int i = 1 ; i <= n ; ++ i )   scanf ( "%d", a + i ) ;    for ( int i = 1 ; i <= n ; ++ i )   ave += a [i] ;    ave /= ( 1.0 * m ) ;    for ( register int i = 1 ; i <= 5000 ; ++ i )   smin ( ans, SA ( ) ) ;    return printf ( "%.2lf\n", sqrt ( ans / ( 1.0 * m ) ) ), 0 ;    }
原创粉丝点击