题解 P2503 【[HAOI2006]均分数据】
思路
模拟退火套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));
}