voidSA(){ double x = ans::x, y = ans::y; for (double t = 1e4; t > 1e-10; t *= 0.998) { double nx = x + random(-t, t), ny = y + random(-t, t); double de = calc(nx, ny) - calc(x, y); if (exp(-de / t) > random(0, 1)) x = nx, y = ny; } }
intmain(){ srand(20230818); scanf("%d", &n); for (int i = 0; i < n; i++) { int x, y, m; scanf("%d%d%d", &x, &y, &m); objs[i] = {x, y, m}; ans::x += x, ans::y += y; } ans::x /= n, ans::y /= n; calc(ans::x, ans::y);
while ((double)clock() / CLOCKS_PER_SEC < 0.8) SA();
if (fabs(ans::x) < 1e-4) ans::x = 0; if (fabs(ans::y) < 1e-4) ans::y = 0; printf("%.3lf %.3lf\n", ans::x, ans::y); return0; }
均分数据
已知 N 个正整数:A1、A2、……、An。
今要将它们分成 M 组,使得各组数据的数值和最平均,即各组的均方差最小。
均方差公式如下:
σ=m∑i=1m(xi−x)2,x=m∑i=1mxi
其中 xi 代表第 i 组数据的数值和。
首先,在退火的过程中我们需要随机挑两个数交换位置,然后进行概率跳转。对于如何将一个数划分成 m 组,这里当然也可以随机搞,但是可以做一步贪心,每次将数字放到数值和(即 xi)最小的一组中,这样尽可能使方差小。
constint N = 25, M = 10; int x[M], w[N], n, m; double ans = 1e9, avg = 0;
doublecalc(){ memset(x, 0, sizeof x); for (int i = 0; i < n; i++) { // 选出当前最小的坑 int t = 0; for (int j = 0; j < m; j++) if (x[j] < x[t]) t = j; x[t] += w[i]; } // 求方差 double res = 0; for (int i = 0; i < m; i++) res += (x[i] - avg) * (x[i] - avg); res /= m; ans = min(res, ans); return res; }
voidSA(){ random_shuffle(w, w+n); for (int t = 1e4; t > 1e-6; t *= 0.99) { int a = rand() % n, b = rand() % n; double pre = calc(); swap(w[a], w[b]); double now = calc(), delta = now - pre; // 如果概率跳转没成功就换回来 if (exp(-delta / t) < (double)rand() / RAND_MAX) swap(w[a], w[b]); } }
intmain(){ srand(20200614); scanf("%d%d", &n, &m); for (int i = 0; i < n; i++) { scanf("%d", &w[i]); avg += w[i]; } avg /= m; while ((double)clock() / CLOCKS_PER_SEC < 0.8) SA(); // 防止 -0 if (fabs(ans) < 1e-3) puts("0.00"); elseprintf("%.2lf\n", sqrt(ans)); return0; }
球形空间产生器
有一个球形空间产生器能够在 n 维空间中产生一个坚硬的球体。
现在,你被困在了这个 n 维球体中,你只知道球面上 n+1 个点的坐标,你需要以最快的速度确定这个 n 维球体的球心坐标,以便于摧毁这个球形空间产生器。
voidSA(){ double x = ans::x, y = ans::y; for (double t = 1e4; t > 1e-10; t *= 0.998) { double nx = x + random(-t, t), ny = y + random(-t, t); double de = calc(nx, ny) - calc(x, y); if (exp(-de / t) > random(0, 1)) x = nx, y = ny; } }
intmain(){ srand(20230818); scanf("%d", &n); for (int i = 0; i < n; i++) { int x, y, m; scanf("%d%d%d", &x, &y, &m); objs[i] = {x, y, m}; ans::x += x, ans::y += y; } ans::x /= n, ans::y /= n; calc(ans::x, ans::y);
while ((double)clock() / CLOCKS_PER_SEC < 0.8) SA();
if (fabs(ans::x) < 1e-4) ans::x = 0; if (fabs(ans::y) < 1e-4) ans::y = 0; printf("%.3lf %.3lf\n", ans::x, ans::y); return0; }
constint N = 15; int q[N], n, ans = 1e9; int refl[N]; bool st[N][N], g[N][N];
doublecalc(){ memset(st, 0, sizeof st); // 构造反映射 for (int i = 1; i <= n; i++) refl[q[i]] = i;
int res = 0; for (int i = 1; i <= n; i++) { for (int j = 1; j <= n; j++) { if (!g[i][j] || st[i][j]) continue; int cost = abs(refl[i] - refl[j]); res += cost; st[i][j] = st[j][i] = true; } } ans = min(res, ans); return res; }
voidSA(){ random_shuffle(q+1, q+1+n); for (double t = 1e8; t >= 1e-8; t *= 0.998) { int a = rand() % n + 1, b = rand() % n + 1; double pre = calc(); swap(q[a], q[b]); double now = calc(), dt = now - pre; if (exp(dt / t) < (double)rand() / RAND_MAX) swap(q[a], q[b]); } }
intmain(){ srand(20230818); scanf("%d", &n); for (int i = 1; i <= n; i++) { int a, b, c; scanf("%d%d%d", &a, &b, &c); g[i][a] = g[i][b] = g[i][c] = true; } for (int i = 1; i <= n; i++) q[i] = i;
while ((double)clock() / CLOCKS_PER_SEC < 0.8) SA(); printf("%d\n", ans);
typedeflonglong LL; constint N = 35; int n, w[N]; LL ans;
intcalc(){ int mid = n/2; // 0~mid-1 mid~n-1 LL l = 0, r = 0; for (int i = 0; i < mid; i++) l += w[i]; for (int i = mid; i < n; i++) r += w[i]; LL res = abs(l-r); ans = min(res, ans); return res; }
voidSA(){ random_shuffle(w, w+n); for (double t = 1e4; t > 1e-4; t *= 0.99) { int a = rand() % n, b = rand() % n; int pre = calc(); swap(w[a], w[b]); int now = calc(), dt = now - pre; if (exp((double)-dt / t) < (double)rand() / RAND_MAX) swap(w[a], w[b]); } }
#define now ((double)clock() / CLOCKS_PER_SEC)
intmain(){ srand(20230818); int T; scanf("%d", &T); // Time per case double tpc = 0.8 / T; while (T--) { double start = now; scanf("%d", &n); ans = 1e18; for (int i = 0; i < n; i++) scanf("%d", &w[i]); while (now - start < tpc) SA(); printf("%lld\n", ans); } return0; }