9
17
2015
0

[BZOJ2428] [HAOI2006] 均分数据

新知识get:模拟退火

设置一个温度T,T越小越不随机

然后做个几万遍就可以了。

#include<cstdio>
#include<cstdlib>
#include<cmath>
#include<cstring>
#include<algorithm>
using namespace std;
 
double ans=2147483647,average=0;
int n,m,a[10005],sum[10005],zu[10005];
 
void Fire(){
double T=10000,nowans=0;
memset(sum,0,sizeof(sum));
for(int i=1;i<=n;i++){
    zu[i]=rand()%m+1;
    sum[zu[i]]+=a[i];
}
for(int i=1;i<=m;i++){
    nowans+=(sum[i]-average)*(sum[i]-average);
}
while(T>0.1){
    T*=0.9;
    int Nx,Ny,R=rand()%n+1;
    Nx=zu[R];
    if(T>500){
        int sa=2147483647,sb;
        for(int i=1;i<=m;i++){
            if(sa>sum[i]){
                sa=sum[i];
                sb=i;
            }
        }
        Ny=sb;
    }
    else Ny=rand()%m+1;
    if(Nx==Ny)continue;
    double lastans=nowans;
    nowans-=(sum[Nx]-average)*(sum[Nx]-average);
    nowans-=(sum[Ny]-average)*(sum[Ny]-average);
    sum[Nx]-=a[R];
    sum[Ny]+=a[R];
    nowans+=(sum[Nx]-average)*(sum[Nx]-average);
    nowans+=(sum[Ny]-average)*(sum[Ny]-average);
    if(nowans<=lastans){zu[R]=Ny;}
    else {
        if(rand()%10000>T){
            sum[Nx]+=a[R];
            sum[Ny]-=a[R];
            nowans=lastans;
        }
        else {
            zu[R]=Ny;
        }
    }
}
ans=min(nowans,ans);
}
 
int main(){
srand(19990720);
scanf("%d %d",&n,&m);
for(int i=1;i<=n;i++){
    scanf("%d",&a[i]);
    average+=a[i];
}
average/=m;
for(int i=1;i<=10000;i++){
    Fire();
}
printf("%.2lf\n",sqrt(ans/m));
return 0;
}
Category: BZOJ | Tags: OI | Read Count: 640

登录 *


loading captcha image...
(输入验证码)
or Ctrl+Enter

Host by is-Programmer.com | Power by Chito 1.3.3 beta | Theme: Aeros 2.0 by TheBuckmaker.com