bzoj2428: [HAOI2006]均分数据

题目链接

bzoj2428: [HAOI2006]均分数据

题解

模拟退火即可

代码

#include<cmath>
#include<cstdio>
#include<cstring>
#include<algorithm>
const int maxn = 100007;
int a[maxn];
double avr,tmpans,ans = 2515656;
int sum[maxn];  
int pos[maxn],n,m; 
double Random() {return (double) rand() / RAND_MAX;}  
void SA() { 
    memset(sum,0,sizeof sum);  
    double tmpx ,tmpy; 
    for(int i = 1;i <= n;++ i) { 
        pos[i] = rand() % m + 1; 
        sum[pos[i]] += a[i]; 
    } 
    for(int i = 1;i <= n;++ i) tmpans += (sum[i] - avr) * (sum[i] - avr); 
    for(double T = 10000;T > 0.001;T *= 0.98) {   
        int x = rand() % n + 1,block; 
        if(T > 500) block = std::min_element(sum + 1,sum + 1 + m) - sum;
        else block = rand() % m + 1; 
        if(pos[x] == block) continue;
        double tmp = tmpans; 
        tmpans -= (sum[pos[x]] - avr) * (sum[pos[x]] - avr);
        tmpans -= (sum[block] - avr) * (sum[block] - avr);
        sum[pos[x]] -= a[x];sum[block] += a[x]; 
        tmpans += (sum[pos[x]] - avr) * (sum[pos[x]] - avr);
        tmpans += (sum[block] - avr) * (sum[block] - avr);
        double DE =  tmp - tmpans; 
        if(DE > 0 || Random() <= exp(DE/T))  pos[x] = block;
        else sum[pos[x]] += a[x],sum[block] -= a[x],tmpans = tmp;
        ans = std::min(ans,tmpans); 
    } 
}
int main() {
     srand(19260817); 
    scanf("%d%d",&n,&m);  
    for(int i = 1;i <= n;++ i) 
        scanf("%lf",a + i) ,avr += a[i];    
    avr /= m;
        for(int k = 5;k --;) SA();  
    printf("%.2lf\n",sqrt(ans/m)); 
    return 0; 
}
posted @ 2018-05-06 14:44  zzzzx  阅读(126)  评论(0编辑  收藏  举报