模拟退火。挺好理解的。然后res打成了ans一直WA一直WA。。。!!!一定要注意嗷嗷嗷一定要注意嗷嗷嗷一定要注意嗷嗷嗷。
然后我就一直卡一直卡。。。发现最少1800次的时候就可以出解了。然后我就去调T的参数。0.85/0.82都会WA。因为T的变化幅度太大。0.95/0.92都能A。
bzoj#31挺开心的。
#include<cstdio>
#include<cstring>
#include<cctype>
#include<algorithm>
#include<cmath>
#include<ctime>
using namespace std;
#define rep(i,s,t) for(int i=s;i<=t;i++)
#define dwn(i,s,t) for(int i=s;i>=t;i--)
#define clr(x,c) memset(x,c,sizeof(x))
const int nmax=1e3+5;
int a[nmax],be[nmax],b[nmax],n,m;
double ans=1e30,sm=0;
void SA(){
double res=0,T=10000,tmp,temp;int u,v,d;
clr(b,0);
rep(i,1,n) u=rand()%m+1,be[i]=u,b[u]+=a[i];
rep(i,1,m) res+=(b[i]-sm)*(b[i]-sm);
while(T>0.1){
u=rand()%n+1;v=be[u];T*=0.9;
if(T>500) d=min_element(b+1,b+m+1)-b;
else d=rand()%m+1;
if(v==d) continue;
tmp=res;
res-=(b[v]-sm)*(b[v]-sm)+(b[d]-sm)*(b[d]-sm);
b[v]-=a[u];b[d]+=a[u];
res+=(b[v]-sm)*(b[v]-sm)+(b[d]-sm)*(b[d]-sm);
if(res<=tmp) be[u]=d;
else if(rand()%10000>T) b[v]+=a[u],b[d]-=a[u],res=tmp;
else be[u]=d;
}
ans=min(ans,res);
}
int main(){
srand(100000007);
scanf("%d%d",&n,&m);
rep(i,1,n) scanf("%d",&a[i]),sm+=a[i];
sm/=(double)m;
rep(i,1,1800) SA();
printf("%.2lf\n",sqrt(ans/m));
return 0;
}
2428: [HAOI2006]均分数据
Time Limit: 5 Sec Memory Limit: 128 MB
Submit:
1699 Solved: 517
[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
1 2 3 4 5 6
Sample Output
0.00
HINT
对于全部的数据,保证有K<=N <= 20,2<=K<=6