模拟退火。挺好理解的。然后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 ",sqrt(ans/m)); return 0; }
2428: [HAOI2006]均分数据
Time Limit: 5 Sec Memory Limit: 128 MBSubmit: 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