【BZOJ2428】[HAOI2006]均分数据

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

Sample Output

0.00

HINT

 

对于全部的数据,保证有K<=N <= 20,2<=K<=6

 
传说中的模拟退火裸题,此处OTZ CA 爷
在我看来模拟退火就是一种特别看人品的贪心,不停地取随机数,也不知道最后能不能用上,毕竟我人品超级差
 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<cmath>
 5 #include<ctime>
 6 #include<cstdlib>
 7 #include<algorithm>
 8 using namespace std;
 9 int n,m,sum1;
10 int a[30],grp[30];
11 double sum[30],tmp,minn=10000000,ave=0;
12 double sqr(double x)
13 {
14     return x*x;
15 }
16 void solve(){
17     memset(sum,0,sizeof(sum));tmp=0;
18     for (int i=1;i<=n;i++) grp[i]=rand()%m+1;
19     for (int i=1;i<=n;i++) sum[grp[i]]+=a[i];
20     for (int i=1;i<=m;i++) tmp+=sqr(sum[i]-ave);
21     double T=17500;
22     while (T>0.1){
23         T*=0.9;
24         int t=rand()%n+1,x=grp[t],y;
25         if (T>500) y=min_element(sum+1,sum+m+1)-sum;
26         else y=rand()%m+1;
27         if (x==y) continue;
28         double last=tmp;
29         tmp-=sqr(sum[x]-ave);tmp-=sqr(sum[y]-ave);
30         sum[x]-=a[t];sum[y]+=a[t];
31         tmp+=sqr(sum[x]-ave);tmp+=sqr(sum[y]-ave);
32         if (rand()%10000>T&&tmp>last) sum[x]+=a[t],sum[y]-=a[t],tmp=last;
33         else grp[t]=y;
34     }
35     minn=min(minn,tmp);
36 }
37  
38 int main(){
39     scanf("%d%d",&n,&m);
40     for (int i=1;i<=n;i++)scanf("%d",&a[i]),
41     sum1+=a[i],swap(a[i],a[rand()%i+1]);
42     ave=(sum1+0.0)/m;
43     for (int i=1;i<=10000;i++)
44     solve();
45     printf("%.2lf\n",sqrt(minn/m));
46 }

 

posted @ 2016-01-24 21:52  Alisahhh  阅读(373)  评论(0编辑  收藏  举报