bzoj 2428 均分数据
题目大意:
已知N个正整数
将它们分成M组,使得各组数据的数值和最平均,即各组的均方差最小
求最小均方差
思路:
模拟退火
1 #include<iostream> 2 #include<cstdio> 3 #include<cmath> 4 #include<cstdlib> 5 #include<cstring> 6 #include<algorithm> 7 #include<queue> 8 #include<vector> 9 #define ll long long 10 #define MAXN 10100 11 #define inf 2139062143 12 using namespace std; 13 inline int read() 14 { 15 int x=0,f=1;char ch=getchar(); 16 while(!isdigit(ch)) {if(ch=='-') f=-1;ch=getchar();} 17 while(isdigit(ch)) {x=x*10+ch-'0';ch=getchar();} 18 return x*f; 19 } 20 double ans=inf,avg; 21 int n,m,a[MAXN],s[MAXN],bl[MAXN]; 22 void work() 23 { 24 double T,tmp,res=0; 25 memset(s,0,sizeof(s)); 26 for(int i=1;i<=n;i++) 27 bl[i]=rand()%m+1,s[bl[i]]+=a[i]; 28 for(int i=1;i<=m;i++) res+=(s[i]-avg)*(s[i]-avg); 29 T=10000; 30 while(T>0.1) 31 { 32 T*=0.9; 33 int t=rand()%n+1,x=bl[t],y; 34 if(T>500) y=min_element(s+1,s+m+1)-s; 35 else y=rand()%m+1; 36 if(x==y) continue; 37 tmp=res; 38 res-=(s[x]-avg)*(s[x]-avg)+(s[y]-avg)*(s[y]-avg); 39 s[x]-=a[t],s[y]+=a[t]; 40 res+=(s[x]-avg)*(s[x]-avg)+(s[y]-avg)*(s[y]-avg); 41 if(res<=tmp) bl[t]=y; 42 else if(rand()%10000>T) s[x]+=a[t],s[y]-=a[t],res=tmp; 43 else bl[t]=y; 44 } 45 if(res<ans) ans=res; 46 } 47 int main() 48 { 49 srand(19260817); 50 n=read(),m=read(); 51 for(int i=1;i<=n;i++) a[i]=read(),avg+=a[i]; 52 avg/=(double)m; 53 for(int i=1;i<=10000;i++) work(); 54 printf("%.2lf\n",sqrt(ans/m)); 55 }