bzoj2428: [HAOI2006]均分数据
2428: [HAOI2006]均分数据
Time Limit: 5 Sec Memory Limit: 128 MBSubmit: 1671 Solved: 506
[Submit][Status][Discuss]
Description
已知N个正整数:A1、A2、……、An 。今要将它们分成M组,使得各组数据的数值和最平均,即各组的均方差最小。均方差公式如下:
,其中σ为均方差,是各组数据和的平均值,xi为第i组数据的数值和。
Input
第一行是两个整数,表示N,M的值(N是整数个数,M是要分成的组数)
第二行有N个整数,表示A1、A2、……、An。整数的范围是1--50。
(同一行的整数间用空格分开)
Output
这一行只包含一个数,表示最小均方差的值(保留小数点后两位数字)。
Sample Input
6 3
1 2 3 4 5 6
1 2 3 4 5 6
Sample Output
0.00
HINT
对于全部的数据,保证有K<=N <= 20,2<=K<=6
退火+数据挺弱的...代码里有注释
1 #include<bits/stdc++.h> 2 #define rep(i,l,r) for(int i=l;i<=r;++i) 3 using namespace std; 4 const int N=10233; 5 typedef double d; 6 d ans=1e30,ave; 7 int n,m,a[N],sum[N],bel[N]; 8 inline void run(){ 9 memset(sum,0,sizeof sum); 10 rep(i,1,n) bel[i]=rand()%m+1,sum[bel[i]]+=a[i]; 11 d sm=0,T=1000; 12 rep(i,1,m) sm+=(sum[i]-ave) * (sum[i]-ave); 13 while(T>0.0001) { //退火温度 14 T*=0.95; 15 int t=rand()%n+1,x=bel[t],y; 16 // if(T>500) y=min_element(sum+1,sum+1+m)-sum; //温度太高时波动大 取当前元素之和最小的一组 奇怪的东西不明为何 17 y=rand()%m+1; //低温度开rand 18 if(x==y) continue; 19 d tmp=sm; 20 sm-=(sum[x]-ave)*(sum[x]-ave); 21 sm-=(sum[y]-ave)*(sum[y]-ave); 22 sum[x]-=a[t],sum[y]+=a[t]; 23 sm+=(sum[x]-ave)*(sum[x]-ave); 24 sm+=(sum[y]-ave)*(sum[y]-ave); 25 if(sm<=tmp) bel[t]=y; //爬山 26 else if((rand()%10000)>T){ //不动 27 sum[x]+=a[t]; sum[y]-=a[t]; 28 sm=tmp; 29 }else bel[t]=y; //动 30 ans=min(ans,sm); 31 } 32 } 33 int main(){ 34 srand(19990720); 35 cin>>n>>m; 36 rep(i,1,n) cin>>a[i],ave+=a[i]; ave/=(d)m; 37 rep(i,1,5000) run(); 38 printf("%.2lf\n",sqrt(ans/m)); 39 }