关闭

2428: [HAOI2006]均分数据

259人阅读 评论(0) 收藏 举报
分类:

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

[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 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;
}

0
0

查看评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
    个人资料
    • 访问:164912次
    • 积分:8592
    • 等级:
    • 排名:第2563名
    • 原创:733篇
    • 转载:1篇
    • 译文:0篇
    • 评论:19条
    文章分类
    最新评论