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 }
View Code

 

posted @ 2018-05-02 19:26  jack_yyc  阅读(168)  评论(0编辑  收藏  举报