bzoj2428: [HAOI2006]均分数据

垃圾bzoj本机AC提交WA,精A

%你退火可解

因为n很小所以我们可以降温慢点,为了更优我们先在开始的时候选择一个数贪心地放到总和最小地那一组

然后就是不停换随机种子T_T

#include<cstdio>
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<cmath>
using namespace std;
double sqr(double x){return x*x;}
double drand(){return double(rand()%10000)/10000.0;}

int n,m,p[30];double a[30],mmin;
double sum[30];
double calc()
{
    memset(sum,0,sizeof(sum));
    for(int i=1;i<=n;i++)sum[p[i]]+=a[i];
    
    double ave=0;
    for(int i=1;i<=m;i++)ave+=sum[i];
    ave/=double(m);
        
    double ret=0;
    for(int i=1;i<=m;i++)ret+=sqr(ave-sum[i]);
    ret=sqrt(ret/(double)m);
    if(ret<mmin)mmin=ret;
    return ret;
}
void annealing()
{
    double T=1000000.0;

    while(T>1)
    {
        double k1=calc();
        
        int pp=1;
        for(int i=1;i<=m;i++)
            if(sum[i]<sum[pp])pp=i;
            
        int x=rand()%n+1,np;
        while(p[x]==pp){x++;if(x==n+1)x=1;}
        
        np=p[x],p[x]=pp;
        double k2=calc();
        
        if(k1>k2||exp((k1-k2)/T)>drand());
        else p[x]=np;
        
        T*=0.9997;
    }
    
    while(T>0.0001)
    {
        int x=rand()%n+1,pp=rand()%m+1,np;
        if(pp==p[x]){pp++;if(pp==m+1)pp=1;}
        
        double k1=calc();
        np=p[x],p[x]=pp;
        double k2=calc();
        
        if(k1>k2||exp((k1-k2)/T)>drand());
        else p[x]=np;
        
        T*=0.9997;
    }
    
    for(int i=1;i<=1000;i++)
    {
        int x=rand()%n+1,pp=rand()%m+1,np;
        if(pp==p[x]){pp++;if(pp==m+1)pp=1;}
        
        double k1=calc();
        np=p[x],p[x]=pp;
        double k2=calc();
        p[x]=np;
    }
}

int main()
{
    srand(25424);
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++)
        scanf("%lf",&a[i]), p[i]=rand()%m+1;
    random_shuffle(a+1,a+n+1);
    
    mmin=calc();
    annealing();
    printf("%.2lf",mmin);
    return 0;
}

 

posted @ 2018-11-27 13:01  AKCqhzdy  阅读(132)  评论(0编辑  收藏  举报