BZOJ2428: [HAOI2006]均分数据 模拟退火

原创 2017年01月03日 19:41:40

题意:N个数分成M组,要求均方差最小
N<=20,M<=6
随机一种分法,然后模拟退火,每次把一个数随机分到另外一组,若rand(0,1)< exp(dt/T)则判定为成功。然而WA了很久,最后知道温度高的时候需要贪心把它放入当前和最小的一组。。。还是不行,于是改成了从头模拟退火20次才终于过了,慢得垫底,真玄学

#include<cstdio>
#include<cstdlib>
#include<cmath>
#include<cstring>
using namespace std;
int n,m;
int w[20],a[20][21],t[20],sum[20],pos[20];
inline double F()
{
    int asum=0;
    for(int i=0;i<m;++i)
    {
        sum[i]=0;
        for(int j=1;j<=t[i];++j)
        sum[i]+=w[a[i][j]];
        asum+=sum[i];
    }
    double dx=floor(asum)/m,res=0;
    for(int i=0;i<m;++i)
    res+=(sum[i]-dx)*(sum[i]-dx);
    return res;
}
inline int move(int x,int p)
{
    int b=pos[x];
    for(int i=t[b]--;;--i)
    {
        if(a[b][i]==x)
        {
            for(;i<=t[b];++i)
            a[b][i]=a[b][i+1];
            break;
        }
    }
    a[p][++t[pos[x]=p]]=x;
    return b;
}
inline bool failed(const double &dt,const double &T)
{
    return dt<0.0&&exp(dt/T)<=floor(rand())/RAND_MAX;
}
inline void random_shuffle()
{
    int aim;
    for(int i=0;i<n;++i)
    {
        pos[i]=aim=rand()%m;
        a[aim][++t[aim]]=i;
    }
}
inline int greedy_choice()
{
    int minn=0x7fffffff,res;
    for(int i=0;i<m;++i)
    {
        sum[i]=0;
        for(int j=1;j<=t[i];++j)
        sum[i]+=w[a[i][j]];
        if(sum[i]<minn) minn=sum[i],res=i;
    }
    return res;
}
inline double fire()
{
    memset(t,0,sizeof t);
    double T=1e16,ans,dt,res;
    int ele,aim,org;
    random_shuffle();
    res=ans=F();
    while(T>1e-10)
    {
        ele=rand()%n;
        if(T>1e2) aim=greedy_choice();
        else aim=rand()%m;
        org=move(ele,aim);
        dt=ans-F();
        if(ans-dt<res) res=ans-dt;
        if(failed(dt,T)) move(ele,org);
        else ans-=dt;
        T*=0.999;
    }
    return res;
}
inline void min(double &a,const double &b)
{
    if(b<a) a=b;
}
int main()
{
    srand(114514);
    scanf("%d%d",&n,&m);
    for(int i=0;i<n;++i)
    scanf("%d",w+i);
    double ans=1e10;
    for(int i=1;i<=20;++i)
    min(ans,sqrt(fire()/m));
    printf("%.2lf\n",ans);
    return 0;
}
版权声明:本文为博主原创文章,未经博主允许不得转载。

相关文章推荐

bzoj2428 [HAOI2006]均分数据 模拟退火

题目大意: 把n个数分成m组,要求分的尽量平均,即方差最小,求这个方差。题目分析: http://blog.csdn.net/lych_cys/article/details/50843232 ...
  • Todobe
  • Todobe
  • 2017年06月21日 16:31
  • 124

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

ATP今晚要不要请假回家睡觉呢。。。
  • FromATP
  • FromATP
  • 2017年03月25日 11:28
  • 286

BZOJ2428 [HAOI2006]均分数据(模拟退火算法)

【题解】 随机10000次左右,每次随机生成初始分组情况,判断将某个元素移入另一组是否会更优,记录全局最优答案  注意: 1. 自己用平方取中法弄的伪随机数,效果远不如系统函数rand() ...
  • cjk_cjk
  • cjk_cjk
  • 2015年06月06日 00:29
  • 465

bzoj2428 均分数据 爬山算法or模拟退火

爬山法和模拟退火的本质是差不多的,在本题中就是得到一个初解后,随机一个数改变到哪一组(组别在步长较大的时候选择和最小的,步长较小的时候随机选择)中,然后比较是否更优,更优就跳过去;如果不更优,则模拟退...

bzoj 2428 均分数据 模拟退火

模拟退火 按照自己的思路打了,结果WA,发现退火最关键的就是初温,降温,和修改次数, 这个题还在外层带了一个循环,骚气 #include #include #include #include #...

洛谷P2503 BZOJ2428 [HAOI2006]均分数据

题目描述:已知N个正整数:A1、A2、……、An 。今要将它们分成M组,使得各组数据的数值和最平均,即各组的均方差最小。均方差公式如下: 输入输出格式 输入格式: 输入文件data.in包括...

bzoj 2428 [HAOI2006]均分数据

Description 已知N个正整数:A1、A2、……、An 。今要将它们分成M组,使得各组数据的数值和最平均,即各组的均方差最小Solution 这题一眼看不会做啊,这题肯定是乱搞题啊。。。一...

模拟退火——BZOJ2428/Luogu2503 [HAOI2006]均分数据

题面:Luogu2503 BZOJ2428 这题使用其他的常规算法不太现实,所以我们想一些奇怪的方法 模拟退火其实就可以(这题拿来入门了) 我们首先把每个数随机分组,然后随机地把一个数从原来的组...

BZOJ 2428 模拟退火 解题报告

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

BZOJ 3680 吊打XXX 模拟退火

首先这题应该改名叫吊打出题人 题目大意:给定n个质点,求重心 这n个质点的重心满足Σ(重心到点i的距离)*g[i]最小 模拟退火的裸题 尼玛交了两篇 死活过不去 各种改参数 最后发现是我的IN...
  • PoPoQQQ
  • PoPoQQQ
  • 2014年09月16日 20:17
  • 3130
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:BZOJ2428: [HAOI2006]均分数据 模拟退火
举报原因:
原因补充:

(最多只允许输入30个字)