已知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
Sample Output
0.00
HINT
对于全部的数据,保证有K<=N <= 20,2<=K<=6
题解
第一次写模拟退火,总结一下就是看人品233,我换了好几个人的生日,结果五花八门,就当放个板子在这里了。
#include<cstdio>
#include<cstdlib>
#include<ctime>
#include<cmath>
#include<cstring>
#include<string>
#include<algorithm>
#include<iostream>
#include<iomanip>
using namespace std;
int ans[25];
int mid[25];
double sum[6];
int n,k;
int val[25];
double trueans=2147483647;
double ax;
double zong=0;
double get_fangcha(int a[])
{
double re=0;
memset(sum,0,sizeof(sum));
for(int i=1;i<=n;i++) sum[a[i]]+=val[i];
for(int i=0;i<k;i++) re+=(sum[i]-ax)*(sum[i]-ax);
re/=k;
return sqrt(re);
}
void SA(double T)
{
double nowans=get_fangcha(ans);
if(nowans<trueans) trueans=nowans;
while(T>0.00001)
{
T*=0.99;
get_fangcha(ans);
int t=rand()%n+1;
int y=rand()%k;
if(ans[t]==y) continue;
int yuan=ans[t];
ans[t]=y;
double newans=get_fangcha(ans);
double rate=exp((nowans-newans)/T);
double tt=rand()%65536;
tt/=65536.0;
if(tt<rate) nowans=newans;
else ans[t]=yuan;
if(nowans<trueans) trueans=nowans;
}
}
int main()
{
srand(19991005);
scanf("%d%d",&n,&k);
for(int i=1;i<=n;i++) scanf("%d",&val[i]),zong+=val[i];
ax=zong/k;
for(int hhh=1;hhh<=500;hhh++)
{
for(int i=1;i<=n;i++)
{
ans[i]=rand()%k;
mid[i]=ans[i];
}
SA(get_fangcha(ans));
}
printf("%.2lf\n",trueans);
}