2428: [HAOI2006]均分数据
Time Limit: 5 Sec Memory Limit: 128 MBSubmit: 1660 Solved: 500
[ Submit][ Status][ Discuss]
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
1 2 3 4 5 6
Sample Output
0.00
HINT
对于全部的数据,保证有K<=N <= 20,2<=K<=6
Source
#include<iostream>
#include<cstdio>
#include<queue>
#include<vector>
#include<bitset>
#include<algorithm>
#include<cstring>
#include<map>
#include<stack>
#include<set>
#include<cmath>
#include<ctime>
#include<ext/pb_ds/priority_queue.hpp>
using namespace std;
typedef double DB;
int n,m,a[22],belong[22];
DB Ave,ans = 1E18,sum[10];
DB Pow(DB x) {return x*x;}
void Fire()
{
for (int i = 1; i <= m; i++)
sum[i] = 0;
for (int i = 1; i <= n; i++) {
int Num = rand()%m + 1;
sum[Num] += a[i];
belong[i] = Num;
}
DB Now = 0;
for (int i = 1; i <= m; i++)
Now += Pow(sum[i] - Ave);
DB T = 10000;
while (T > 0.1) {
T *= 0.9;
int x = rand()%n + 1;
DB tmp = Now,k = a[x];
int A = belong[x],B;
if (T > 500) {
DB Min = 1E18;
for (int i = 1; i <= m; i++)
if (sum[i] < Min)
Min = sum[i],B = i;
}
else B = rand()%m + 1;
if (A == B) continue;
Now -= Pow(sum[A] - Ave);
Now -= Pow(sum[B] - Ave);
sum[A] -= k;
sum[B] += k;
Now += Pow(sum[A] - Ave);
Now += Pow(sum[B] - Ave);
if (Now > tmp) {
int pass = rand()%10000;
if (pass > T) {
sum[A] += k;
sum[B] -= k;
Now = tmp;
continue;
}
}
belong[x] = B;
}
ans = min(ans,Now);
}
int main()
{
#ifdef DMC
freopen("DMC.txt","r",stdin);
#endif
//srand(19990720);
cin >> n >> m;
for (int i = 1; i <= n; i++) {
scanf("%d",&a[i]);
Ave += (DB)(a[i]);
}
Ave /= (DB)(m);
for (int i = 1; i <= 10000; i++)
Fire();
printf("%.2lf",sqrt(ans/(DB)(m)));
return 0;
}