2428: [HAOI2006]均分数据

来源:互联网 发布:李云龙 赵刚 知乎 编辑:程序博客网 时间:2024/05/16 16:00

2428: [HAOI2006]均分数据

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

Sample Output

0.00

HINT

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

Source

Day2

[Submit][Status][Discuss]

RP算法--模拟退火
主要思路如下:
随机选出一组解,,此时可能离正解很遥远,我们随机地去更新,随着时间的推移,这个解离正解的距离也会越来越近,最后停止,即得出正解
一开始随意地把元素置入各个分组,每次随机一个元素,将它放到别的组里面去,一开始我们可能离正解很远,就贪心找一个当前元素和最小的分组,把这个元素放进去,看能不能更优,随着时间的推移,离正解越来越近,此时贪心不一定可行,就随机一个分组,把这个元素放进去
当改变了一个元素所属分组,如果新的ans优于当前的,就接受它,否则以一定概率接受它,这个概率一定是随着时间推移不断降低的
#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 DMCfreopen("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;}

0 0
原创粉丝点击