BZOJ2428:[HAOI2006]均分数据
我对模拟退火的理解: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]均分数据的更多相关文章
- bzoj2428: [HAOI2006]均分数据
模拟退火.挺好理解的.然后res打成了ans一直WA一直WA...!!!一定要注意嗷嗷嗷一定要注意嗷嗷嗷一定要注意嗷嗷嗷. 然后我就一直卡一直卡...发现最少1800次的时候就可以出解了.然后我就去调 ...
- bzoj2428 [HAOI2006]均分数据 模拟退火
[HAOI2006]均分数据 Time Limit: 5 Sec Memory Limit: 128 MBSubmit: 3434 Solved: 1091[Submit][Status][Dis ...
- BZOJ2428[HAOI2006]均分数据——模拟退火
题目描述 已知N个正整数:A1.A2.…….An .今要将它们分成M组,使得各组数据的数值和最平均,即各组的均方差最小.均方差公式如下: ,其中σ为均方差,是各组数据和的平均值,xi为第i组数据的数值 ...
- BZOJ2428 HAOI2006均分数据(模拟退火)
显然可以状压dp.显然过不了. 考虑暴力模拟退火.每次随机改变一个数所属集合即可. 并不明白要怎么调参. #include<iostream> #include<cstdio> ...
- 【BZOJ2428】均分数据(模拟退火)
[BZOJ2428]均分数据(模拟退火) 题面 BZOJ 题解 先说说黄学长的做法: 当温度比较高的时候,贪心 每次随机一个数,把他放进当前和最少的那一组里面 温度足够低的时候就完全随机然后转移 这样 ...
- P2503 [HAOI2006]均分数据
P2503 [HAOI2006]均分数据 模拟退火+dp (不得不说,我今天欧气爆棚) 随机出1个数列,然后跑一遍dp统计 #include<iostream> #include<c ...
- bzoj 2428: [HAOI2006]均分数据 随机化
2428: [HAOI2006]均分数据 Time Limit: 20 Sec Memory Limit: 256 MB 题目连接 http://www.lydsy.com/JudgeOnline/ ...
- 洛谷 P2503 [HAOI2006]均分数据 随机化贪心
洛谷P2503 [HAOI2006]均分数据(随机化贪心) 现在来看这个题就是水题,但模拟赛时想了1个小时贪心,推了一堆结论,最后发现贪心做 不了, 又想了半个小时dp 发现dp好像也做不了,在随机化 ...
- 【BZOJ2428】[HAOI2006]均分数据
Description 已知N个正整数:A1.A2.…….An .今要将它们分成M组,使得各组数据的数值和最平均,即各组的均方差最小.均方差公式如下: ,其中σ为均方差,是各组数据和的平均值,xi为第 ...
- BZOJ2428:[HAOI2006]均分数据——题解
https://www.lydsy.com/JudgeOnline/problem.php?id=2428 https://www.luogu.org/problemnew/show/P2503 已知 ...
随机推荐
- EF之POCO应用系列2——复杂类型
在.NET开发中,EF4以前的版本以及LINQ TO SQL都不支持complex数据类型,EF4终于支持complex类型的数据了,这意味着微软的EF框架朝领域驱动方面又迈了一大步. 复杂的数据类型 ...
- 低秩近似 low-rank approximation
- Redis通过PUBLISH / SUBSCRIBE 等命令实现了订阅与发布模式
# 切换目录 [root@localhost /]# cd /opt/redis-4.0.10 # 启动客户端 -p 指定端口 [root@localhost ~]# redis-cli -p 638 ...
- 我的Android进阶之旅------>Android之动画之Frame Animation实例
============================首先看看官网上关于Frame animation的介绍================================ 地址:http://de ...
- 淘宝开放平台php-sdk测试 获取淘宝商品信息(转)
今天想使用淘宝开放平台的API获取商品详情,可是以前一直没使用过,看起来有点高深莫测,后然看开发入门,一步一步,还真有点感觉了,然后看示例,还真行了,记下来以后参考.其中遇到问题,后然解决了.因为我已 ...
- ABAP制作密码输入框
[转自 http://blog.csdn.net/saphome/article/details/6956911] 这几天做一个系统维护的程序,需要用户输入用户名和密码登录.可怎样实现输入密码显示星号 ...
- sql获取数组长度
需求:获取字符串数组1,2,3,4的长度,当然也可以是其他分隔符1|2|3等 方法:通过自定义函数来实现 /* 获取字符串数组长度 */ from sysobjects where id = obje ...
- 冒泡排序的三种实现(Java)
冒泡排序是非常好理解的,以从小到大排序为例,每一轮排序就找出未排序序列中最大值放在最后. 设数组的长度为N: (1)比较前后相邻的二个数据,如果前面数据大于后面的数据,就将这二个数据交换. (2)这样 ...
- python基础4 ----字符编码
python基础---字符编码 一.了解字符编码 1. 文本编辑器存取文件的原理(nodepad++,pycharm,word) 打开编辑器就打开了启动了一个进程,是在内存中的,所以在编辑器编写的内容 ...
- hadoop1.2.1 datanode 由于权限无法启动 expected: rwxr-xr-x
/************************************************************ STARTUP_MSG: Starting DataNode STARTUP ...