【Luogu】P3052摩天大楼里的奶牛(遗传算法乱搞)

  一道状压题,但今天闲来无事又用遗传乱搞了一下。

  设了一个DNA数组,DNA[i]记录第i个物品放在哪个组里。适应度是n-这个生物的组数+1.

  交配选用的是轮盘赌和单亲繁殖——0.3的几率单点变异。(事实上有性生殖我似乎写不出来……代码量略大)

  种群大小开到了400,在vijos上繁殖了2050代,下数据自己测也是对的。

 然而只有84分

   这究竟是为什么啊    下数据自己测是没错的啊………………

  疯了

  代码和数据先放到这里,以后再改吧

  

#include<cstdio>
#include<cctype>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<ctime>

inline double random(double from,double to){
    return rand()*1.0/RAND_MAX*(to-from)+from;
}

inline long long read(){
    long long num=0,f=1;
    char ch=getchar();
    while(!isdigit(ch)){
        if(ch=='-')    f=-1;
        ch=getchar();
    }
    while(isdigit(ch)){
        num=num*10+ch-'0';
        ch=getchar();
    }
    return num*f;
}

int n;
int w[10000],W;
int ans=0x7fffffff;

struct Creative{
    int DNA[19],s[19];
    int cnt,score;
    Creative(){    cnt=0;score=0;    memset(s,0,sizeof(s));    }
    Creative Create(){
        Creative New;
        for(register int i=1;i<=n;++i){
            if(New.cnt==0||random(0,1)<=0.5){
                New.cnt++;
                New.DNA[i]=New.cnt;
                New.s[New.cnt]+=w[i];
            }
            else{
                int j,tot=0;
                Label:
                    tot++;
                    j=random(1,New.cnt);
                    if(New.s[j]+w[i]>W&&tot<=n*2)    goto Label;
                    if(!New.s[j]&&tot<=n+10)            goto Label;
                if(tot>=n*2){
                    New.cnt++;
                    New.DNA[i]=New.cnt;
                    New.s[New.cnt]+=w[i];
                    continue;
                }
                New.DNA[i]=j;
                New.s[j]+=w[i];
            }
        }
        if(New.cnt)    ans=std::min(ans,New.cnt);
        New.score=n-New.cnt+1;
        return New;
    }
};

struct Biome{
    Creative e[402];
    int tot;
    void Clear(bool flag){
        tot=0;
        for(int i=1;i<401;++i){
            if(flag)    e[i]=e[i].Create();
            if(e[i].cnt)    tot+=e[i].score;
            if(e[i].cnt==0)    i--;
        }
    }
    int Find(){
        int sum=0,limit=random(1,tot);
        for(register int i=1;i<401;++i){
            sum+=e[i].score;
            if(sum>=limit)    return i;
        }
        return 400;
    }
    Creative Multi(int x){
        Creative New=e[x];
        if(random(0,1)>0.3)    return New;
        int i=random(1,n+1),pos=New.DNA[i];
        New.s[pos]-=w[i];
        if(!New.s[pos]){
            New.cnt--;
            New.score++;
        }
        int j,tot=0;
        Label:
            tot++;
            j=random(1,n);
            if(New.s[j]+w[i]>W&&tot<=n*2)        goto Label;
            if(!New.s[j]&&tot<=n+10)            goto Label;
        if(tot>=n*2){
            New.cnt++;
            New.DNA[i]=New.cnt;
            New.score--;
            New.s[New.cnt]+=w[i];
        }
        else{
            New.DNA[i]=j;
            if(!New.s[j]){
                New.cnt++;
                New.score--;
            }
            New.s[j]+=w[i];
            ans=std::min(ans,New.cnt);
        }
        return New;
    }
}Old,New;

inline bool cmp(Creative a,Creative b){    return a.score>b.score;    }

int main(){
    srand(time(NULL));
    n=read(),W=read();
    for(int i=1;i<=n;++i)    w[i]=read();
    Old.Clear(1);
    for(register int T=1;T<=700;++T){
        Old.Clear(0);
        for(register int i=1;i<401;++i)    New.e[i]=Old.Multi(Old.Find());
        std::sort(Old.e+1,Old.e+401,cmp);
        std::sort(New.e+1,New.e+401,cmp);
        for(register int i=1;i<=100;++i)    Old.e[300+i]=New.e[i];
    }
    /*for(int i=1;i<=100;++i,printf("
")){
        for(int j=1;j<=n;++j)    printf("%d ",Old.e[i].DNA[j]);
        printf(">>>%d %d",Old.e[i].cnt,Old.e[i].score);
    }*/
    printf("%d",ans);
    return 0;
}

18 100000000
37597832
24520955
100000000
18509980
29141223
20287969
14028193
33097076
12116817
53439913
10216168
32891936
43952038
13463011
4056577
4646046
10153053
37881213

下一个准备用遗传搞的题是猫狗大战。

原文地址:https://www.cnblogs.com/cellular-automaton/p/7678915.html