P2503 [HAOI2006]均分数据

P2503 [HAOI2006]均分数据

模拟退火+dp

(不得不说,我今天欧气爆棚)

随机出1个数列,然后跑一遍dp统计

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cctype>
#include<cstdlib>
#include<cmath>
#include<ctime>
#define re register
using namespace std;
template <typename T> inline T min(T &a,T &b) {return a<b ?a:b;}
template <typename T> inline T max(T &a,T &b) {return a>b ?a:b;}
template <typename T> inline void read(T &x){
    char c=getchar(); x=0; bool f=1;
    while(!isdigit(c)) f= !f||c=='-' ? 0:1,c=getchar();
    while(isdigit(c)) x=(x<<3)+(x<<1)+(c^48),c=getchar();
    x= f ? x:-x;
}
template <typename T> inline T squ(T a) {return a*a;}
typedef double db;
int n,m,a[23],sum[23];
db f[23][23],ans=1e15,ave;
inline db calc(){ //dp:设f[i][j]表示当前为第i个位置,分成j块
    memset(f,127,sizeof(f)); f[0][0]=0;
    for(re int i=1;i<=n;++i) sum[i]=sum[i-1]+a[i];
    for(re int i=1;i<=n;++i)
        for(re int j=1;j<=i;++j)
            for(re int k=0;k<i;++k)
                f[i][j]=min(f[i][j],f[k][j-1]+squ(sum[i]-sum[k]-ave));
    return f[n][m];
}
inline void smt(){
    for(db t=2000;t>1e-14;t*=0.993){ //自行修改
        int x=rand()%n+1,y=rand()%n+1;
        swap(a[x],a[y]); //随机交换2个数字
        db _val=calc(),delta=_val-ans;
        if(delta<0) ans=_val;
        else if(exp(-delta/t)*RAND_MAX<=rand()) swap(a[x],a[y]); //一定概率接受非最优解
    }
}

int main(){
    srand(19260817); srand(rand()); srand(rand());
    read(n),read(m);
    for(re int i=1;i<=n;++i) read(a[i]),ave+=a[i];
    ave=ave/(db)m;
    while((db)clock()/CLOCKS_PER_SEC<0.825) smt(); //卡时。可以先看下跑一遍退火时间多少,再修改限制值(记得多留点时间给下面的代码)
    printf("%.2lf",sqrt(ans/(db)m));
    return 0;
}

 

转载于:https://www.cnblogs.com/kafuuchino/p/9722557.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值