代码如下,其中的命名解释:
val: 每个数据的值
grp: 数据分到的组号
sum: 每个组的数据和
avg: sum 的平均数
ans: 答案
sig: 本次尝试的标准差
delta: sig - ans
sq(): 平方
getSig(): 获取当前标准差
#include <iostream>
#include <cmath>
#include <random>
constexpr double COOLDOWN(0.999), EPS(1e-15);
constexpr int MAXN(22);
using namespace std;
namespace Answer {
int n, m, val[MAXN], grp[MAXN], sum[MAXN];
double avg, ans;
inline double sq(double x) { return x * x; }
double getSig() {
double ret(0.0);
for (int i(1); i <= m; ++ i)
ret += sq(sum[i] - avg);
return sqrt(ret / m);
}
void sa() {
int x, y;
double temp(100.0), nSig, delta;
while (temp > EPS) {
do {
x = rand() % n + 1;
y = rand() % n + 1;
} while (x == y);
sum[grp[x]] -= val[x] - val[y];
sum[grp[y]] -= val[x] - val[y];
delta = (nSig = getSig()) - ans;
if (delta < 0 || exp(-delta / temp) * RAND_MAX > rand()) {
grp[x] ^= grp[y] ^= grp[x] ^= grp[y];
ans = nSig;
} else {
sum[grp[x]] += val[x] - val[y];
sum[grp[y]] += val[x] - val[y];
}
temp *= COOLDOWN;
}
return;
}
void main() {
scanf("%d%d", &n, &m);
for (int i(1); i <= n; ++ i) {
scanf("%d", val + i);
avg += val[i];
sum[grp[i] = i % m + 1] += val[i];
}
avg /= m;
ans = getSig();
sa();
sa();
sa();
sa();
sa();
sa();
sa();
printf("%.2lf", ans);
return;
}
}
int main() {
Answer::main();
return 0;
}