1. 程式人生 > >BZOJ2428 HAOI2006均分數據(模擬退火)

BZOJ2428 HAOI2006均分數據(模擬退火)

-- bzoj read const 隨機 sin bsp har ++

  顯然可以狀壓dp。顯然過不了。

  考慮暴力模擬退火。每次隨機改變一個數所屬集合即可。

  並不明白要怎麽調參。

#include<iostream> 
#include<cstdio>
#include<cmath>
#include<cstdlib>
#include<cstring>
#include<algorithm>
using namespace std;
int read()
{
    int x=0,f=1;char c=getchar();
    while (c<0||c>9
) {if (c==-) f=-1;c=getchar();} while (c>=0&&c<=9) x=(x<<1)+(x<<3)+(c^48),c=getchar(); return x*f; } #define N 21 #define T0 1E5 #define T1 1E-6 #define v 0.996 int n,m,a[N],sum[N],id[N],size[N]; double ave,ans=100000000; void anneal() { for (int i=1;i<=m;i++) id[i]=i,sum[i]=a[i],size[i]=1
; for (int i=m+1;i<=n;i++) id[i]=rand()%m+1,sum[id[i]]+=a[i],size[id[i]]++; double T=T0,tot=0; for (int i=1;i<=m;i++) tot+=(sum[i]-ave)*(sum[i]-ave); if (m<n) while (T>T1) { int x=rand()%n+1; while (size[id[x]]==1) x=rand()%n+1; int y=rand()%m+1
; while (id[x]==y) y=rand()%m+1; if (rand()<exp((-2.0*a[x]*(a[x]-sum[id[x]]+sum[y]))/T)*RAND_MAX) { tot+=2*a[x]*(a[x]-sum[id[x]]+sum[y]); sum[y]+=a[x],sum[id[x]]-=a[x]; size[y]++,size[id[x]]--; id[x]=y; } T*=v; ans=min(ans,tot); } } int main() { #ifndef ONLINE_JUDGE freopen("bzoj2428.in","r",stdin); freopen("bzoj2428.out","w",stdout); const char LL[]="%I64d\n"; #else const char LL[]="%lld\n"; #endif srand(20020509); n=read(),m=read(); for (int i=1;i<=n;i++) ave+=a[i]=read(); ave/=m; for (int i=1;i<=200;i++) anneal(); printf("%.2lf",sqrt(ans/m)); return 0; }

BZOJ2428 HAOI2006均分數據(模擬退火)