您的位置:首页 > 其它

bzoj 2428: [HAOI2006]均分数据

2016-03-29 23:11 369 查看
模拟退火;

#include<bits/stdc++.h>
#define rep(i,k,n) for(int i=k;i<=n;i++)
using namespace std;
double ave=0.0,ans=0.0,tmp=0.0,T=10000.0,minans=1e30;
int n,m,sum[30],belong[30],a[30];
void fire(){T=10000.0;
memset(sum,0,sizeof(sum));
ans=0.0;
for(int i=0;i<n;i++){int xx=rand()%m;sum[xx]+=a[i];belong[i]=xx;}
for(int i=0;i<m;i++){ans+=(sum[i]*1.0-ave)*(sum[i]*1.0-ave);}
while(T>0.1){
T*=0.9;
int t=rand()%n,y;int x=belong[t];
if(T>500)
y=min_element(sum,sum+m)-sum;
else y=rand()%m;
if(x==y)continue;
tmp=ans;
ans-=(sum[x]*1.0-ave)*(sum[x]*1.0-ave);
ans-=(sum[y]*1.0-ave)*(sum[y]*1.0-ave);
sum[x]-=a[t];sum[y]+=a[t];
ans+=(sum[x]*1.0-ave)*(sum[x]*1.0-ave);
ans+=(sum[y]*1.0-ave)*(sum[y]*1.0-ave);
if(ans<=tmp)
belong[t]=y;
else if(rand()%10000>T){
sum[x]+=a[t];sum[y]-=a[t];
ans=tmp;
}
else belong[t]=y;
minans=min(minans,ans);
}
}
int main(){
//freopen("in.in","r",stdin);
srand('L'+'T'+'Q');
scanf("%d%d",&n,&m);
for(int i=0;i<n;i++){scanf("%d",&a[i]);ave+=(a[i]*1.0);
}ave/=(double)m;
rep(i,1,10000)
fire();
printf("%.2lf",sqrt(minans/m));
}


很神奇也很好玩的算法,我也就在bzoj上玩了20几遍罢了…尝试各种参数…
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: