关于遗传算法:

读完知乎上一篇关于遗传算法的介绍,感觉确实挺有意思的,于是决定写一个程序应用一下试试。
首先重新回忆一下高中生物知识:

判断一个图和最优解的接近程度(选择函数):对于该图,不断向该图中所含水滴数最多的格子内添水,直到该图水滴
数为0时停止,记录该办法所添加的水滴数。
第一代:随机向图中几个格加点儿水。
杂交:从上一代中随机取出两组,用随机函数将他们分成新的两组。得到的新的两组,如果有一步是要向一个空格子内
添加水滴,那么这一步绝对没好处,所以在这时我选择违背自然规律删掉这一步,从而得到一个更好的子代。
选择:用选择函数,让离最优解越远的选择方法出现的概率越少。
变异:自认为很重要,因为它可以引入新的可能性。因为之前所有的操作都只会减少操作步数,不会使操作步数增加,
所以我决定随机添加操作步数模拟变异。所以对于每一组,都有百分之x的可能性在该组后面再添加一步操作。

代码:

//十滴水,启发式算法
/*-------------------------------------------------------------------------------------------------------- 读完知乎上一篇关于遗传算法的介绍,感觉确实挺有意思的,于是决定写一个程序应用一下试试。 首先重新回忆一下高中生物知识: 判断一个图和最优解的接近程度(选择函数):对于该图,不断向该图中所含水滴数最多的格子内添水,直到该图水滴 数为0时停止,记录该办法所添加的水滴数。 第一代:随机向图中几个格加点儿水。 杂交:从上一代中随机取出两组,用随机函数将他们分成新的两组。得到的新的两组,如果有一步是要向一个空格子内 添加水滴,那么这一步绝对没好处,所以在这时我选择违背自然规律删掉这一步,从而得到一个更好的子代。 选择:用选择函数,让离最优解越远的选择方法出现的概率越少。 变异:自认为很重要,因为它可以引入新的可能性。因为之前所有的操作都只会减少操作步数,不会使操作步数增加, 所以我决定随机添加操作步数模拟变异。所以对于每一组,都有百分之x的可能性在该组后面再添加一步操作。 --------------------------------------------------------------------------------------------------------*/
#include<bits/stdc++.h>

/*#include<iostream> #include<math.h> #include<stdio.h> #include<vector> #include<stdlib.h> #include<time.h> #include<string.h> #include<algorithm>*/

using namespace std;




const int GENERATION=100;//培育代数
const int UNIT_NUM=1000;//每代培育个数
int step_unit_num[36*4]={0};//step_unit_num[i]=x表示适应函数值为 i 的个体个数为 x
int my_map[6][6];//储存原地图




struct ADD_STEP//在某一点增加水滴(模拟基因)
{
    int x;int y;
};
struct UNIT//由若干个有序基因组成的个体(模拟生物)
{
    vector<ADD_STEP>gene;
    //int fit;//描述生物的适应程度
};
UNIT unit[UNIT_NUM];
UNIT unit_2[UNIT_NUM];
UNIT best;
ADD_STEP my_way[36];



bool Unit_cmp(UNIT x , UNIT y)
{
    return x.gene.size()<y.gene.size();
}

bool Map_empty( int (*m)[6] )
{
    for(int i=0;i<6;i++)
    {
        for(int j=0;j<6;j++)
        {
            if(m[i][j]!=0)return 0;
        }
    }
    return 1;
}

void Init()//用一种我觉得比较好的顺序来加水。设置搜索路径基本思路:从中间到两边。
{
    my_way[0].x=3;my_way[0].y=3;    my_way[1].x=3;my_way[1].y=4;    my_way[2].x=4;my_way[2].y=3;
    my_way[3].x=4;my_way[3].y=4;    my_way[4].x=2;my_way[4].y=3;    my_way[5].x=5;my_way[5].y=4;
    my_way[6].x=3;my_way[6].y=5;    my_way[7].x=4;my_way[7].y=2;    my_way[8].x=5;my_way[8].y=3;
    my_way[9].x=4;my_way[9].y=5;    my_way[10].x=3;my_way[10].y=2;  my_way[11].x=2;my_way[11].y=4;
    my_way[12].x=2;my_way[12].y=5;  my_way[13].x=5;my_way[13].y=5;  my_way[14].x=5;my_way[14].y=2;
    my_way[15].x=2;my_way[15].y=2;  my_way[16].x=1;my_way[16].y=3;  my_way[17].x=6;my_way[17].y=4;
    my_way[18].x=4;my_way[18].y=1;  my_way[19].x=3;my_way[19].y=6;  my_way[20].x=4;my_way[20].y=6;
    my_way[21].x=3;my_way[21].y=1;  my_way[22].x=6;my_way[22].y=3;  my_way[23].x=1;my_way[23].y=4;
    my_way[24].x=1;my_way[24].y=5;  my_way[25].x=6;my_way[25].y=2;  my_way[26].x=1;my_way[26].y=2;
    my_way[27].x=5;my_way[27].y=6;  my_way[28].x=6;my_way[28].y=5;  my_way[29].x=2;my_way[29].y=6;
    my_way[30].x=2;my_way[30].y=1;  my_way[31].x=5;my_way[31].y=1;  my_way[32].x=6;my_way[32].y=1;
    my_way[33].x=6;my_way[33].y=6;  my_way[34].x=1;my_way[34].y=6;  my_way[35].x=1;my_way[35].y=1;
}

void Boom(int (*m)[6] , int x , int y)//坐标(x,y)爆炸!
{
    m[x][y]=0;
    int lx=x,ly=y;
    while(1)
    {
        lx--;
        if(lx<0)break;
        if(m[lx][ly]!=0)
        {
            m[lx][ly]++;
            if(m[lx][ly]>4)
            {
                Boom(m,lx,ly);
            }
            break;
        }
    }
    lx=x;
    while(1)
    {
        lx++;
        if(lx>=6)break;
        if(m[lx][ly]!=0)
        {
            m[lx][ly]++;
            if(m[lx][ly]>4)
            {
                Boom(m,lx,ly);
            }
            break;
        }
    }
    lx=x;
    while(1)
    {
        ly--;
        if(ly<0)break;
        if(m[lx][ly]!=0)
        {
            m[lx][ly]++;
            if(m[lx][ly]>4)
            {
                Boom(m,lx,ly);
            }
            break;
        }
    }
    ly=y;
    while(1)
    {
        ly++;
        if(ly>=6)break;
        if(m[lx][ly]!=0)
        {
            m[lx][ly]++;
            if(m[lx][ly]>4)
            {
                Boom(m,lx,ly);
            }
            break;
        }
    }
}

void Add_map(int (*m)[6], int x , int y)//对一个图的(x,y)位置添加一滴水之后得到的新图
{
    m[x][y]++;
    if(m[x][y]>4)Boom(m,x,y);
}

ADD_STEP Find_way( int (*m)[6] )
{
    for(int i=4;i>0;i--)
    {
        for(int j=0;j<36;j++)
        {
            if(m[my_way[j].x][my_way[j].y]==i)return my_way[j];
        }
    }
}


void Fit_step(int (*m)[6] , UNIT & this_unit)//找出地图的适应程度,并且补全余剩走法
{
    int test_map[6][6];
    for(int i=0;i<6;i++)
    {
        for(int j=0;j<6;j++)
        {
            test_map[i][j]=m[i][j];
        }
    }

    for(int i=0;i<this_unit.gene.size();i++)
    {
        if(Map_empty(test_map))
        {
            while(this_unit.gene.size()!=i)
            {
                this_unit.gene.pop_back();

            }
            break;
        }
        Add_map( test_map , this_unit.gene[i].x , this_unit.gene[i].y );

    }
    while(!Map_empty(test_map))
    {
        this_unit.gene.push_back( Find_way(test_map) );
        //this_unit.fit++;

        Add_map( test_map , this_unit.gene[this_unit.gene.size()-1].x , this_unit.gene[this_unit.gene.size()-1].y );

    }
    //cout<<this_unit.gene.size()<<" ";
}


/*------------------------------------------------------------------------------------------------------ 初代种群每个生物基因组成为:首先随机产生3个有序位置,然后使用补全走法。 注意这里可能会出现bug,因为如果随机产生的两个正好可以消去所有的水滴,那么生成随机数的循环将无法跳出。 -------------------------------------------------------------------------------------------------------*/
void Produce_first()//产生初代种群
{
    memset(step_unit_num,0,sizeof(step_unit_num));
    srand( (unsigned)time( NULL ) );
    for(int i=0;i<UNIT_NUM;i++)
    {
        /*int test_map[6][6]; for(int j=0;j<6;j++) { for(int k=0;k<6;k++) { test_map[j][k]=my_map[j][k]; } }*/
        for(int j=0;j<3;j++)//假设初代每个个体基因数为3
        {
            ADD_STEP k;
            k.x=rand()%6;k.y=rand()%6;
            //cout<<k.x<<k.y<<endl;
            unit[i].gene.push_back(k);
        }
        Fit_step( my_map , unit[i] );
        //if(unit[i].gene.size()<3)cout<<unit[i].gene.size()<<" ";
        step_unit_num[unit[i].gene.size()]++;
        if(best.gene.size()>unit[i].gene.size())
        {
            best=unit[i];
        }
    }
    sort(unit,unit+UNIT_NUM,Unit_cmp);
}
/*------------------------------------------------------------------------------------------------------*/


/*-------------------------------------------------------------------------------------------------------- 选择函数:保证了每一个适应值为 x 的生物存活的几率为适应值为 x+1 的生物的存活几率的 2 倍。 ----------------------------------------------------------------------------------------------------------*/
int choose()
{
    int S=UNIT_NUM;
    int K=0;
    for(int i=0;i<GENERATION;i++)
    {
        for(int j=1;j<=36*4;j++)
        {
            int x=rand()%(S+step_unit_num[j]);
            if(x<step_unit_num[j]*2)
            {
                return x/2+K;
            }
            K+=step_unit_num[j];
            S-=step_unit_num[j];
        }
    }
}

/*-------------------------------------------------------------------------------------------------------- 交配: --------------------------------------------------------------------------------------------------------*/
void Born()//让编号为 x 的生物和编号为 y 的生物交配,产生两个新个体。
{
    int x,y;
    for(int i=0;i<UNIT_NUM;i+=2)//假定种群数量为偶数
    {
        x=choose();
        y=choose();
        //cout<<x<<" "<<y<<endl;
/*---------------------------------------生成第一个生物--------------------------------------------------*/
        for(int j=0;j<(unit[x].gene.size()+1)/2;j++)//这里如果是奇数,那么将会多取一个
        {
            unit_2[i].gene.push_back(unit[x].gene[j]);
        }
        for(int j=0;j<(unit[y].gene.size()+1)/2;j++)//这里如果是奇数,那么将会多取一个
        {
            unit_2[i].gene.push_back(unit[y].gene[j+unit[y].gene.size()/2]);
        }
/*--------------------------------------------------------------------------------------------------------*/

/*---------------------------------------生成第二个生物--------------------------------------------------*/
        for(int j=0;j<(unit[y].gene.size()+1)/2;j++)//这里如果是奇数,那么将会多取一个
        {
            unit_2[i+1].gene.push_back(unit[y].gene[j]);
        }
        for(int j=0;j<(unit[x].gene.size()+1)/2;j++)//这里如果是奇数,那么将会多取一个
        {
            unit_2[i+1].gene.push_back(unit[x].gene[j+unit[x].gene.size()/2]);
        }
/*--------------------------------------------------------------------------------------------------------*/

/*------------------------------------------基因突变------------------------------------------------------*/
        if(rand()%1000==1)
        {
            ADD_STEP l;
            l.x=rand()%6;
            l.y=rand()%6;
            unit_2[i+rand()%2].gene.push_back(l);
        }

/*--------------------------------------------------------------------------------------------------------*/
        Fit_step(my_map,unit_2[i]);
        Fit_step(my_map,unit_2[i+1]);
    }
    memset(step_unit_num,0,sizeof(step_unit_num));
    for(int i=0;i<UNIT_NUM;i++)
    {
        unit[i]=unit_2[i];
        step_unit_num[unit[i].gene.size()]++;
        if(best.gene.size()>unit[i].gene.size())
        {
            best=unit[i];
            cout<<best.gene.size()<<endl;
        }
    }
    sort(unit,unit+UNIT_NUM,Unit_cmp);
}

void Input()
{
    for(int i=0;i<6;i++)
    {
        for(int j=0;j<6;j++)
        {
            cin>>my_map[i][j];
        }
    }
}

void Output()
{
    for(int i=0;i<best.gene.size();i++)
    {
        cout<<best.gene[i].x+1<<" "<<best.gene[i].y+1<<endl;
    }
}
int main()
{
    Init();
    Input();
    Fit_step(my_map,best);
    cout<<best.gene.size()<<endl;
    Produce_first();

    for(int i=0;i<GENERATION;i++)
    {
        Born();
        cout<<i<<" "<<best.gene.size()<<endl;
    }
    cout<<best.gene.size()<<endl;
    Output();
}

代码待改。。。。