码迷,mamicode.com
首页 > 其他好文 > 详细

BZOJ2428: [HAOI2006]均分数据

时间:2018-02-09 22:33:25      阅读:153      评论:0      收藏:0      [点我收藏+]

标签:through   space   ==   print   bsp   pre   element   algo   div   

Description

已知N个正整数:A1、A2、……、An 。今要将它们分成M组,使得各组数据的数值和最平均,即各组的均方差最小。均方差公式如下:

技术分享图片,,其中σ为均方差,技术分享图片是各组数据和的平均值,xi为第i组数据的数值和。

Input

第一行是两个整数,表示N,M的值(N是整数个数,M是要分成的组数)
第二行有N个整数,表示A1、A2、……、An。整数的范围是1--50。
(同一行的整数间用空格分开)

Output

这一行只包含一个数,表示最小均方差的值(保留小数点后两位数字)。

Sample Input

6 3
1 2 3 4 5 6

Sample Output

0.00

HINT

对于全部的数据,保证有K<=N <= 20,2<=K<=6

 

题目传送门

 

我真的是闲的蛋疼才会去搞模拟退火这个东西

这道题算是模拟退火入门题吧。。。

先说说做这道题之前,我想了一个很垃圾的DP,不知道能不能过

然后就没想法了,于是去%题解:模拟退火

关于这个早有耳闻,据说很考RP

那么他其实还是一个贪心,就是加了随机性:在前期,变量很大,我们取得了一个较优解,但是还是有很大几率接受一个较差解

然后随着时间推进,我们没有时间限制可以败家了,然后把变量改小,取得较差解的几率越来越低,然后的出正确答案

这就是模拟退火

再看这道题,他的n才20,k也才。。卧槽哪来的k?,也不过6

那我们就可以败家一点,给他4000次机会(当然这个数字不确定),每次随机组合,然后随机选数,进行计算,然后随机接受解

在这道题里也有个细节,我们取得了一个较优解,就得保存一下当前这个随机选出来的数,交换位置

然后继续随机进行解。。

神tm这AC也很随机吧。。。

代码如下:

#include<ctime>
#include<cmath>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
using namespace std;
int n,m;
int a[30],unit[30];
double sum[30],tmp,ans=1e30,ave;
double sqr(double x)
{
    return x*x;
}
void solve()
{
    memset(sum,0,sizeof(sum));tmp=0;
    for(int i=1;i<=n;i++)unit[i]=rand()%m+1;
    for(int i=1;i<=n;i++)sum[unit[i]]+=a[i];
    for(int i=1;i<=m;i++)tmp+=sqr(sum[i]-ave);
    double T=17500;
    while(T>0.1)
    {
        T*=0.9;
        int t=rand()%n+1,x=unit[t],y;
        if(T>500)y=min_element(sum+1,sum+m+1)-sum;
        else y=rand()%m+1;
        if (x==y)continue;
        double last=tmp;
        tmp-=sqr(sum[x]-ave);tmp-=sqr(sum[y]-ave);
        sum[x]-=a[t];sum[y]+=a[t];
        tmp+=sqr(sum[x]-ave);tmp+=sqr(sum[y]-ave);
        if(rand()%10000>T&&tmp>last)sum[x]+=a[t],sum[y]-=a[t],tmp=last;
        else unit[t]=y;
    }
    ans=min(ans,tmp);
}
int main()
{
    srand(0);
    scanf("%d%d",&n,&m);
    for (int i=1;i<=n;i++) scanf("%d",&a[i]),ave+=a[i],swap(a[i],a[rand()%i+1]);
    ave/=m;
    for (int i=1;i<=4000;i++)   solve();
    printf("%.2lf\n",sqrt(ans/m));
    return 0;
}

by_lmy

BZOJ2428: [HAOI2006]均分数据

标签:through   space   ==   print   bsp   pre   element   algo   div   

原文地址:https://www.cnblogs.com/MT-LI/p/8436569.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!