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;
}