[BZOJ2428] [HAOI2006]均分数据 && 模拟退火

我真是*了狗了

随机数种子被卡了 我也是醉了 什么给T分段什么的 做几万次模拟退火什么的 根本想不到啊QAQ 

一晚上就被这些鬼模拟退火虐过去了

#include<cstdio>
#include<algorithm>
#include<cstring>
#include<iostream>
#include<queue>
#include<cmath>
#define PF printf
#define SF scanf
using namespace std;
typedef long long LL;
const int MAXN = 20;
double Min, ave, ans = 1e30;
int n, m;
int A[MAXN+10], group[MAXN+10];
double sum[MAXN+10];
inline double Rand() {
	return rand() % 10000 / 10000;
}
inline int find_min() {
	int MIN = 1234567890, p;
	for(int i = 1; i <= m; i++) 
		if(sum[i] < MIN) 
			MIN = sum[i], p = i;
	return p;
}
void SA(int T) {
	memset(sum, 0, sizeof(sum));
	for(int i = 1; i <= n; i++) {
		group[i] = rand() % m + 1;
		sum[group[i]] += A[i];
	}
	double Now = 0, New;
	for(int i = 1; i <= m; i++) 
		Now += (sum[i] - ave) * (sum[i] - ave);
	while(T > 0.1) {
		T *= 0.9;
		int x = rand() % n + 1, from = group[x], to;
		if(T > 500) to = find_min();
		else to = rand() % m + 1;
		if(from == to) continue;
		New = Now;
		New -= (sum[from] - ave) * (sum[from] - ave) + (sum[to] - ave) * (sum[to] - ave);
		sum[from] -= A[x]; sum[to] += A[x];
		New += (sum[from] - ave) * (sum[from] - ave) + (sum[to] - ave) * (sum[to] - ave);
		double dE = Now - New;
		if(dE > 0 || rand() % 10000 <= T) {
            Now = New; group[x] = to;
        }
        else {
            sum[from] += A[x]; sum[to] -= A[x];
        }
        ans = min(ans, Now);
        T *= 0.97;
	}
	
}
int main() {
	srand(23333333);
	SF("%d%d", &n, &m);
	for(int i = 1; i <= n; i++) SF("%d", &A[i]), ave += A[i];
	ave /= 1.0 * m;
	for(int i = 1; i <= 20000; i++) SA(10000);
	PF("%.2f", sqrt(ans/m));
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值