Description
已知N个正整数:A1、A2、……、An 。今要将它们分成M组,使得各组数据的数值和最平均,即各组的均方差最小。
均方差公式如下:
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
题解Here!
懒得复制了,请戳这。
但是不得不说洛谷比BZOJ好多了。。。
至少可以看到怎么错了。。。
看着BZOJ上将近两页的提交记录,不是TLE就是WA啊。。。
是时候祭出这张图了:
参数调试好累啊!!!
所以,代码稍稍改一下:
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cmath>
#include<cstring>
#define MAXN 25
using namespace std;
int n,m;
int belong[MAXN];
double average=0.00,minn=2147483645,val[MAXN],s[MAXN];
inline int read(){
int date=0,w=1;char c=0;
while(c<'0'||c>'9'){if(c=='-')w=-1;c=getchar();}
while(c>='0'&&c<='9'){date=date*10+c-'0';c=getchar();}
return date*w;
}
void SA(){
double T=10000,ans=0.00;
memset(s,0,sizeof(s));
for(int i=1;i<=n;i++){
belong[i]=rand()%m+1;
s[belong[i]]+=val[i];
}
for(int i=1;i<=m;i++)ans+=(s[i]-average)*(s[i]-average);
while(T>1e-4){
double last=ans;
int x=min_element(s+1,s+m+1)-s,y=rand()%n+1;
ans-=(s[belong[y]]-average)*(s[belong[y]]-average)+(s[x]-average)*(s[x]-average);
s[belong[y]]-=val[y];s[x]+=val[y];
ans+=(s[belong[y]]-average)*(s[belong[y]]-average)+(s[x]-average)*(s[x]-average);
if(ans<last||exp((ans-last)/T)*RAND_MAX<rand())belong[y]=x;
else{
ans=last;
s[belong[y]]+=val[y];s[x]-=val[y];
}
T*=0.95;
}
minn=min(minn,ans);
}
void work(){
for(int cases=1;cases<=5000;cases++)SA();
printf("%.2lf\n",sqrt(minn/(double)m));
}
void init(){
srand(2002);
n=read();m=read();
for(int i=1;i<=n;i++){
val[i]=read();
average+=val[i];
}
average/=(double)m;
}
int main(){
init();
work();
return 0;
}