题解 P2503 【[HAOI2006]均分数据】

luogu

思路

模拟退火dp
关于基础的模拟退火欢迎来踩blog
代码正确时交两次A两次(种子随机)
Woc这不是mo你退火的风格啊嘎嘎嘎
看我平衡点那篇博文的辛酸史。。。
这道题其实就是连续分组,用模拟退火打乱不就随机了吗?
然后就只有计算稍微难一点了(描述对一个初二蒟蒻相当不友好啊喂!(σ`д′)σ )
最后放出代码

Code

#include<bits/stdc++.h>
using namespace std;
int n,m,A[30],s[30];
double xs=0.95;//降温系数
double ans=1000000000,qwq,dp[30][30];
double calc()
{
	for(int i=0;i<=n;i++)
	{
		for(int j=0;j<=m;j++)
		{
			dp[i][j]=10000;
		}
	}
	for(int i=1;i<=n;i++)
	{
		s[i]=s[i-1]+A[i];
	}
	dp[0][0]=0;
	for(int i=1;i<=n;i++)
	{
		for(int j=1;j<=i;j++)
		{
			for(int k=0;k<i;k++)
			{
				dp[i][j]=min(dp[i][j],dp[k][j-1]+(s[i]-s[k]-qwq)*(s[i]-s[k]-qwq));
			}		
		}
	}
	ans=min(ans,dp[n][m]);
	return dp[n][m];
}
int SA()//模拟退火
{
	double t=10000,now=ans;
	while(t>0.0001)
	{
		int x=rand()%n+1,y=rand()%n+1;//随机匹配
		swap(A[x],A[y]);
		double res=calc();
		double ch=res-now;
		if(ch<0||exp(-ch)/t>(double)(rand()%100/100.00))
		{
			now=res;
		}
		else
		{
			swap(A[x],A[y]);
		}
		t*=xs;
	}
}
int main()
{
	srand(time(NULL));//随机种子
	cin>>n>>m;
	for(int i=1;i<=n;i++)
	{
		cin>>A[i];
		qwq+=1.0*A[i]/m;
	}
	calc(); 
	while((double)clock()/CLOCKS_PER_SEC<0.8)//卡时限
	{
		SA();
	}
	printf("%.2lf",sqrt(ans/m));
}
posted @ 2019-02-12 10:58  G_A_TS  阅读(470)  评论(0编辑  收藏  举报