2428: [HAOI2006]均分数据
Time Limit: 5 Sec Memory Limit: 128 MBSubmit: 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
1 2 3 4 5 6
Sample Output
0.00
HINT
对于全部的数据,保证有K<=N <= 20,2<=K<=6
第一次写模拟退火……常数设不好。试验了很多次。
971708 | ws_fqk | 2428 | Accepted | 1284 kb | 596 ms | C++/Edit | 1238 B | 2015-05-13 10:47:32 |
971707 | ws_fqk | 2428 | Wrong_Answer | 1284 kb | 404 ms | C++/Edit | 1237 B | 2015-05-13 10:47:10 |
971705 | ws_fqk | 2428 | Wrong_Answer | 1284 kb | 368 ms | C++/Edit | 1240 B | 2015-05-13 10:45:39 |
971704 | ws_fqk | 2428 | Wrong_Answer | 1284 kb | 160 ms | C++/Edit | 1240 B | 2015-05-13 10:45:21 |
971703 | ws_fqk | 2428 | Accepted | 1284 kb | 608 ms | C++/Edit | 1242 B | 2015-05-13 10:44:59 |
971701 | ws_fqk | 2428 | Accepted | 1284 kb | 1172 ms | C++/Edit | 1243 B | 2015-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; }