您的位置:首页 > 其它

[HAOI2006][BZOJ2428] 均分数据

2015-05-13 10:47 225 查看

2428: [HAOI2006]均分数据

Time Limit: 5 Sec Memory Limit: 128 MB
Submit: 801 Solved: 231
[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

Sample Output

0.00

HINT

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

第一次写模拟退火……常数设不好。试验了很多次。

971708ws_fqk2428Accepted1284 kb596 msC++/Edit1238 B2015-05-13 10:47:32
971707ws_fqk2428Wrong_Answer1284 kb404 msC++/Edit1237 B2015-05-13 10:47:10
971705ws_fqk2428Wrong_Answer1284 kb368 msC++/Edit1240 B2015-05-13 10:45:39
971704ws_fqk2428Wrong_Answer1284 kb160 msC++/Edit1240 B2015-05-13 10:45:21
971703ws_fqk2428Accepted1284 kb608 msC++/Edit1242 B2015-05-13 10:44:59
971701ws_fqk2428Accepted1284 kb1172 msC++/Edit1243 B2015-05-13 10:43:58
最后调到了600ms。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<cmath>
#include<vector>
using namespace std;
int n,m,k,pos[21],a[21];
double ave,ans,mn=100000007,sum[21];
void solve()
{
double t=10000; //初始温度
ans=0;
memset(sum,0,sizeof(sum));
for (int i=1;i<=n;i++) pos[i]=rand()%m+1;
for (int i=1;i<=n;i++) sum[pos[i]]+=a[i];
for (int i=1;i<=m;i++) ans+=(sum[i]-ave)*(sum[i]-ave);
while (t>0.1)
{
t*=0.91; //降温速率 0.9时WA。
//-----------------------------------------------------------------------
int t1=rand()%n+1,x=pos[t1],y;
if (t>500) y=min_element(sum+1,sum+m+1)-sum; else y=rand()%m+1;   //随机选取两个位置 为什么>500取最小我也很不解,求解释。
//-----------------------------------------------------------------------
if (x==y) continue;
double pre=ans;
ans-=(sum[x]-ave)*(sum[x]-ave);
ans-=(sum[y]-ave)*(sum[y]-ave);
sum[x]-=a[t1];
sum[y]+=a[t1];
ans+=(sum[x]-ave)*(sum[x]-ave);
ans+=(sum[y]-ave)*(sum[y]-ave);                                   //换位置,更新ans,sum。
//-----------------------------------------------------------------------
if (rand()%10000>t&&ans>pre)
{
sum[x]+=a[t1]; sum[y]-=a[t1];
ans=pre;
}
else pos[t1]=y;
}                                                                     //若不优,则返回原来的值,否则(小于概率或更优)更换位置。
//-----------------------------------------------------------------------
if (ans<mn) mn=ans;
}
int main()
{
scanf("%d%d",&n,&m);
for (int i=1;i<=n;i++)
{
scanf("%d",&a[i]);
ave+=a[i];
}
ave/=m;
for (int i=1;i<=5000;i++) solve();
printf("%.2lf",sqrt(mn/m));
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: