现在的位置: 首页 > 综合 > 正文

【模拟退火】【bzoj 2428】: [HAOI2006]均分数据

2017年04月21日 ⁄ 综合 ⁄ 共 1851字 ⁄ 字号 评论关闭

http://www.lydsy.com/JudgeOnline/problem.php?id=2428


我xxxxxx,运气太好了吧这都能wa。。。。。

srand一下就A了

蒟蒻想问一下,难道生成数据也会用模拟退火嘛。。。?


先把问题转化一下,就是求每组的和的平方的和最小

开始以为是状压DP,发现只有40分。。。

然后冥思苦想,最后看题解,惊呆了——模拟退火


不会调参数,所以各项参数参照hzwer

//#define _TEST _TEST
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <iostream>
#include <cmath>
#include <algorithm>
using namespace std;
/************************************************
Code By willinglive    Blog:http://willinglive.cf
************************************************/
#define rep(i,l,r) for(int i=(l),___t=(r);i<=___t;i++)
#define per(i,r,l) for(int i=(r),___t=(l);i>=___t;i--)
#define MS(arr,x) memset(arr,x,sizeof(arr))
#define LL long long
#define INE(i,u,e) for(int i=head[u];~i;i=e[i].next)
inline const int read()
{int r=0,k=1;char c=getchar();for(;c<'0'||c>'9';c=getchar())if(c=='-')k=-1;
for(;c>='0'&&c<='9';c=getchar())r=r*10+c-'0';return k*r;}
/////////////////////////////////////////////////
int n,m;
int a[22],sum;
double ave=0;
int pos[22],s[22];
/////////////////////////////////////////////////
double cal()
{
	double res=0;
	MS(s,0);
	rep(i,1,n) pos[i]=rand()%m+1;
	rep(i,1,n) s[pos[i]]+=a[i];
	rep(i,1,m) res+=s[i]*s[i];
	double T=10000;
	while(T>0.1)
	{
		T*=0.9;
		int x=rand()%n+1;
		int u=pos[x],v;
		if(T>500) v=min_element(&s[1],&s[m+1])-s;
		else v=rand()%m+1;
		if(u==v) continue;
		double pre=res;
		res-=s[u]*s[u]; res-=s[v]*s[v];
		s[u]-=a[x]; s[v]+=a[x];
		res+=s[u]*s[u]; res+=s[v]*s[v];
		if(rand()%10000>T && res>pre)
		{
			s[u]+=a[x]; s[v]-=a[x];
			res=pre;
		}
		else pos[x]=v;
	}
	return res;
}
/////////////////////////////////////////////////
void input()
{
	srand(13131);
    n=read(); m=read();
    rep(i,1,n)
    {
    	a[i]=read();
    	ave+=a[i]; sum+=a[i];
		swap(a[i],a[rand()%i+1]);
    }
    ave/=m;
}
void solve()
{
	double ans=1e10;
	rep(i,1,10000)
	{
		ans=min(ans,cal());
	}
	printf("%.2lf",sqrt((ans-2*ave*sum+m*ave*ave)/m));
}
/////////////////////////////////////////////////
int main()
{
    #ifndef _TEST
    freopen("std.in","r",stdin); freopen("std.out","w",stdout);
    #endif
    input(),solve();
    return 0;
}

抱歉!评论已关闭.