2428: [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
【解题报告】
参见http://blog.csdn.net/qpswwww/article/details/44161053
代码如下:
/**************************************************************
Problem: 2428
User: onepointo
Language: C++
Result: Accepted
Time:1444 ms
Memory:952 kb
****************************************************************/
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;
#define N 10000
#define inf 0x3f3f3f3f
double min_ans=inf*1.0,ave=0.0;
int n,m;
int a[N],belong[N],sum[N];
inline int q_rand()
{
static int seed=10007;
return seed=int(seed*48271LL%2147483647);
}
void SA()
{
memset(sum,0,sizeof(sum));
for(int i=1;i<=n;++i)
{
belong[i]=q_rand()%m+1;
sum[belong[i]]+=a[i];
}
double ans=0;
for(int i=1;i<=m;++i) ans+=(sum[i]-ave)*(sum[i]-ave);
double T=10000;
while(T>1)
{
T*=0.9;
int t=q_rand()%n+1,x=belong[t],y;
if(T>500) y=min_element(sum+1,sum+m+1)-sum;
else y=rand()%m+1;
if(x==y) continue;
double tmp=ans;
ans-=(sum[x]-ave)*(sum[x]-ave);
ans-=(sum[y]-ave)*(sum[y]-ave);
sum[x]-=a[t],sum[y]+=a[t];
ans+=(sum[x]-ave)*(sum[x]-ave);
ans+=(sum[y]-ave)*(sum[y]-ave);
if(ans<=tmp) belong[t]=y;
else if(q_rand()%10000>T)
{
sum[x]+=a[t],sum[y]-=a[t];
ans=tmp;
}
else belong[t]=y;
}
if(ans<min_ans) min_ans=ans;
}
int main()
{
scanf("%d%d",&n,&m);
for(int i=1;i<=n;++i)
{
scanf("%d",&a[i]);
ave+=a[i];
}
ave/=(double)m;
for(int i=1;i<=10000;++i) SA();
printf("%.2lf\n",sqrt(min_ans/m));
return 0;
}