• 【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

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

  • 相关阅读:
    MySQL日志概述
    MySQL事务概述
    MySQL存储引擎
    Linux软件安装,RPM与YUM
    使用PuTTY在Windows中向Linux上传文件
    Linux网络基础
    Java正则表达式实例详解
    Javascript正则构造函数与正则表达字面量&&常用正则表达式
    常用sql语句及案例(oracle)
    oracle数据导入/导出(2)
  • 原文地址:https://www.cnblogs.com/cellular-automaton/p/7678915.html
Copyright © 2020-2023  润新知