我对模拟退火的理解:https://www.cnblogs.com/AKMer/p/9580982.html

题目传送门:https://www.lydsy.com/JudgeOnline/problem.php?id=2428

遗传算法和爬山算法在\(OJ\)上\(A\)题的可能性太小了,还是退火好,可以对我在\(BZOJ\)的账号做一点贡献。

对于这道题,我们首先得明白状态空间是啥。

这道题要求一个最优的分组方法,使得每一组的权值和的方差最小,那么状态就是\(n\)个数分别放在哪一个组里。

然后我们就可以用一个长度为\(n\)的数组来记录状态,寻找邻居节点的时候随机一个数字,将它放到另一组去就是一个新状态了。然后对于方差最小这个要求,我们可以灵性的贪心一波,比如每次都把这个数字移到权值和最小的那一组去。这样在很大几率上会直接减少方差。

每个状态对应的权值就是该状态分配下的方差。

然后退个六七十遍火就是了。

时间复杂度:\(O(能A)\)

空间复杂度:\(O(能A)\)

代码如下:

#include <cmath>
#include <ctime>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
#define sqr(a) ((a)*(a)) const int maxn=30; const double T_0=1e-7,del_T=0.998; int n,m;//n个数字,m组
double ave,ans;//ave存平均值,ans存历史最小方差
int a[maxn],d[maxn],b[maxn],c[maxn],e[maxn];//a存数字,b[i]存第i个数字当前在第几组,d[i]存第i个数字在历史最优状态下在第几组,c[i]存第i组当前权值,e[i]存第i组在历史最优状态下的权值 int read() {
int x=0,f=1;char ch=getchar();
for(;ch<'0'||ch>'9';ch=getchar())if(ch=='-')f=-1;
for(;ch>='0'&&ch<='9';ch=getchar())x=x*10+ch-'0';
return x*f;
}//快读 double calc(int pos,int group) {//计算把pos号数字放到第group组后的方差
double sum=0;
for(int i=1;i<=m;i++) {
double tmp=c[i]-ave;
if(tmp==b[pos])tmp-=a[pos];
if(tmp==group)tmp+=a[pos];
sum+=sqr(tmp);//按照数学公式计算
}
return sqrt(sum/m);//记得返回double,不然会被卡精度
} void Anneal() {
memcpy(b,d,sizeof(d));
memcpy(c,e,sizeof(e));//每次都从最优状态开始
double T=1e7;//初始温度1e7,结束温度1e-7,del_T为0.998;
while(T>=T_0) {
int group=0,mn=1e9;
for(int i=1;i<=m;i++)
if(c[i]<mn)mn=c[i],group=i;//找最小的那一组编号
int pos=rand()%n+1;
double tmp=calc(pos,group);//计算新状态的答案
if(tmp<ans) {//如果新状态更优
c[b[pos]]-=a[pos];c[group]+=a[pos];
b[pos]=group;ans=tmp;
memcpy(d,b,sizeof(b));
memcpy(e,c,sizeof(c));//直接更新当前状态以及历史最优状态
}
else if(exp((ans-tmp)/T)*RAND_MAX>rand()) {//如果在一定的概率内
c[b[pos]]-=a[pos];c[group]+=a[pos];
b[pos]=group;//直接更新当前状态
}
T*=del_T;//降温
}
} int main() {
srand(time(0));
n=read();m=read();
for(int i=1;i<=n;i++) {
a[i]=read();
b[i]=d[i]=rand()%m+1;
e[d[i]]+=a[i];
c[d[i]]+=a[i];ave+=a[i];
}ave/=m;ans=calc(0,0);//初始化一个状态
for(int i=1;i<=60;i++)
Anneal();//做60遍退火(好像这个代码稍微少一点点就A不了了)
printf("%.2lf\n",ans);//输出答案
return 0;
}

这题也可以用爬山写,和这个代码差不多,大家灵性脑补一波就好。

BZOJ2428:[HAOI2006]均分数据的更多相关文章

  1. bzoj2428: [HAOI2006]均分数据

    模拟退火.挺好理解的.然后res打成了ans一直WA一直WA...!!!一定要注意嗷嗷嗷一定要注意嗷嗷嗷一定要注意嗷嗷嗷. 然后我就一直卡一直卡...发现最少1800次的时候就可以出解了.然后我就去调 ...

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

    [HAOI2006]均分数据 Time Limit: 5 Sec  Memory Limit: 128 MBSubmit: 3434  Solved: 1091[Submit][Status][Dis ...

  3. BZOJ2428[HAOI2006]均分数据——模拟退火

    题目描述 已知N个正整数:A1.A2.…….An .今要将它们分成M组,使得各组数据的数值和最平均,即各组的均方差最小.均方差公式如下: ,其中σ为均方差,是各组数据和的平均值,xi为第i组数据的数值 ...

  4. BZOJ2428 HAOI2006均分数据(模拟退火)

    显然可以状压dp.显然过不了. 考虑暴力模拟退火.每次随机改变一个数所属集合即可. 并不明白要怎么调参. #include<iostream> #include<cstdio> ...

  5. 【BZOJ2428】均分数据(模拟退火)

    [BZOJ2428]均分数据(模拟退火) 题面 BZOJ 题解 先说说黄学长的做法: 当温度比较高的时候,贪心 每次随机一个数,把他放进当前和最少的那一组里面 温度足够低的时候就完全随机然后转移 这样 ...

  6. P2503 [HAOI2006]均分数据

    P2503 [HAOI2006]均分数据 模拟退火+dp (不得不说,我今天欧气爆棚) 随机出1个数列,然后跑一遍dp统计 #include<iostream> #include<c ...

  7. bzoj 2428: [HAOI2006]均分数据 随机化

    2428: [HAOI2006]均分数据 Time Limit: 20 Sec  Memory Limit: 256 MB 题目连接 http://www.lydsy.com/JudgeOnline/ ...

  8. 洛谷 P2503 [HAOI2006]均分数据 随机化贪心

    洛谷P2503 [HAOI2006]均分数据(随机化贪心) 现在来看这个题就是水题,但模拟赛时想了1个小时贪心,推了一堆结论,最后发现贪心做 不了, 又想了半个小时dp 发现dp好像也做不了,在随机化 ...

  9. 【BZOJ2428】[HAOI2006]均分数据

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

  10. BZOJ2428:[HAOI2006]均分数据——题解

    https://www.lydsy.com/JudgeOnline/problem.php?id=2428 https://www.luogu.org/problemnew/show/P2503 已知 ...

随机推荐

  1. 经过两个多月的攻关,终于搞定了live555多线程并稳定压测通过

    live555已经发展了十几年了,不得不钦佩作者坚持不懈的奉献和国外的开源生态环境,live555可以说是大部分的安防从业者的入门之选,尤其是在嵌入式或者Linux系统上,其应用还是蛮广泛的,主要是其 ...

  2. What is MEAN?

    MEAN.JS is a full-stack JavaScript open-source solution, which provides a solid starting point for M ...

  3. BAPI_SALESORDER_CREATEFROMDAT2 创建退货SO

    BAPI_SALESORDER_CREATEFROMDAT2创建退货订单时,会出现以下错误:不允许业务对象 BUS2032 和销售凭证类别 H 的组合. 解决办法: 采用/原BAPI的内嵌BAPI: ...

  4. ABAP table control例子

    [转自]http://blog.csdn.net/lhx20/article/details/3039909Table control用于在screen上以表格的形式显示数据,在table contr ...

  5. LeeCode:两数之和【1】

    LeeCode:两数之和[1] 题目描述 给定一个整数数组和一个目标值,找出数组中和为目标值的两个数. 你可以假设每个输入只对应一种答案,且同样的元素不能被重复利用. 示例: 给定 nums = [2 ...

  6. mysql sql语句:行转列问题

    存在表score,记录学生的考试成绩,如下图所示: 现要求以 学生姓名,语文,数学,英语 这种格式显示学生成绩,如下图所示 具体步骤如下: 1.首先,使用case when函数输出单个课程的成绩 ca ...

  7. Data Structure Binary Tree: Construct Tree from given Inorder and Preorder traversals

    http://www.geeksforgeeks.org/construct-tree-from-given-inorder-and-preorder-traversal/ #include < ...

  8. DEV开发之界面皮肤

    最终效果:正文本人的环境是 VS2013+DEV 13.21.第一步,新建项目,(忽略)???2.修改Form1.cs的基类,Form修改为DevExpress.XtraBars.Ribbon.Rib ...

  9. 浮动float

    一.浮动定义:会强制改变display为inline-block,使元素排队列,(排列方式由属性值决定,left / rihgt), 使该元素处于半脱离文档状态 二.浮动元素处于半飘离状态,能看到浮动 ...

  10. Python核心编程课后习题-第六章

    1. 字符串, string模块中是否有一种字符串方法或者函数可以帮我鉴定一下一个字符串是否是另一个大字符串的一部分? str1 = 'abcdefghijklmnopqrstuv' print st ...