LuoGu P2503 [HAOI2006]均分数据

原题地址
比平衡点还裸的模拟退火模板题,但是窝就是不会打,
太菜了
n个数分m组,让方差最小,就是对于ai把ai放到最小的xi中(1<=x<=n)
对于n个数随机重组
退火很迷的我对着大佬的参数一个一个试下来(真开心嘤嘤嘤)
走好

// luogu-judger-enable-o2
#include <bits/stdc++.h>
using namespace std;
int n,m,a[25],grp[25],sum[25];
double ans,avg;
const double d = 0.992;
double get_val()
{
    double val = 0;
    for (int i = 1;i <= m;i++) 
        val += (sum[i] - avg) * (sum[i] - avg);
    return val / m;
}
void ch_grp(int pos,int target)
{
    sum[grp[pos]] -= a[pos];
    sum[target] += a[pos];
    grp[pos] = target;
}
void SA()
{
    double T = 3000,cur_ans = ans;
    while (T > 1e-10)
    {
        int pos = rand() % n + 1,target = rand() % m + 1;
        int origin = grp[pos]; 
        ch_grp(pos,target);
        double nans = get_val(),diff = nans - cur_ans;
        if (diff < 0)
        {
            cur_ans = nans;if (cur_ans < ans) ans = cur_ans;
        }
        else if (RAND_MAX * exp(-diff / T) <= rand()) ch_grp(pos,origin);
        T *= d;
    }
}
int main ()
{
    srand(time(0));
    scanf("%d%d",&n,&m);
    for (int i = 1;i <= n;i++) 
    {
        scanf("%d",&a[i]);avg += a[i];
    }
    avg /= m;
    for (int i = 1;i <= n;i++)
    {
        grp[i] = rand() % m + 1;sum[grp[i]] += a[i];
    }
    ans = get_val();
    for (int i = 1;i <= 1000;i++) SA();
    printf("%.2lf",sqrt(ans));
    return 0;
}

放弃吧,假的参数,我才不会给你真的呢。

猜你喜欢

转载自blog.csdn.net/qq_15647239/article/details/89461024