luogu P2503 [HAOI2006]均分数据(模拟退火)

思路:模拟退火随机交换两个数,暴力分组,稍微推一下公式

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef double db;
const db down = 0.996;
const db eps = 1e-15;
const int N = 25;

int n, m, a[N], b[N], c[N];
db ans, ave;

db cal() {
    memset(c, 0, sizeof(c));
    for(int i = 1; i <= n; ++i) {
        int pos = 1;
        for(int j = 2; j <= m; ++j)
            if(c[j] < c[pos]) pos = j;
        c[pos] += b[i];
    }
    db ret = 0.0;
    for(int i = 1; i <= m; ++i)
        ret += (1.0 * c[i] - ave) * (1.0 * c[i] + ave);
    return 1.0 * sqrt(ret / m);
}

void sa() {
    db t = 3000;
    while (t > eps) {
        int x = rand() % n + 1, y = rand() % n + 1;
        while(x == y) y = rand() % n + 1;
        swap(b[x], b[y]);
        db ew = cal();
        db de = ew - ans;
        if(de < 0) ans = ew;
        else if(exp(-de / t) * RAND_MAX > rand()) swap(b[x], b[y]);
        t *= down;
    }
}

void solve() {
    for(int i = 1; i <= 4; ++i) {
        memcpy(b, a, sizeof(a));
        sa();
    }
}

int main() {
    srand(19260817);
    scanf("%d%d", &n, &m);
    ave = 0.0;
    for(int i = 1; i <= n; ++i) {
        scanf("%d", &a[i]);
        ave += 1.0 * a[i];
    }
    ave = 1.0 * ave / m;
    memcpy(b, a, sizeof(a));
    ans = cal();
    solve();
    printf("%.2f\n", ans);
    return 0;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值