限制颜色数的图着色---遗传算法

要解决的问题:
只用3种颜色完成图着色,使得冲突的边数最少。实际意义为,将3种PSS分配分配给各小区,使得冲突最少。

数据集:
邻区关系矩阵

#include "iostream"
#include "fstream"
#include "vector"
#include "queue"
#include "algorithm"
#include "ctime"
#include "set"
#include "cstdlib"
using namespace std;

#define POPSIZE 50 //种群规模
#define MAXGENS 1000 //进化代数
#define PXOVER 0.8 //杂交概率
#define PMUTATION 0.15 //变异概率
#define PSELECT 0.85

const int N = 120;     //结点数量
vector<int> G[N];      //邻接表
int cur_best;
int generation;
int x[N];


void Xover(int one, int two);

struct Entity
{
    set<int> gen[3];   //一个染色方案,即顶点集合的一种3-划分
    int fitness;       //适应度,为冲突边数

    bool operator < (Entity node) const  //按适应度从小到大排序
    { 
        return fitness > node.fitness;
    }

    int getFit()
    {
        int fit = 0;
        set<int>::iterator it;
        for(int i=0; i<3; i++)
            for(it=gen[i].begin(); it != gen[i].end(); it++) 
                for(int v=0; v<G[(*it)].size(); v++)   
                    if(gen[i].count(G[*it][v]))     /*如果当前结点与其邻接点在同一个划分中,则冲突*/
                        fit++;
        return fit;
    }
};

Entity population[POPSIZE + 1];     //种群
Entity newpopulation[POPSIZE + 1];  //新种群
priority_queue<Entity> q;           

int num()
{
    int edge = 0;
    for(int i=0; i<N; i++)
        for(int j=0; j<G[i].size(); j++)
            if(x[i]==x[G[i][j]])
                edge++;
    return edge;
}


//返回arr[3]中最小数的下标
int minIndex(int arr[3])
{
    int min = arr[0]<arr[1] ? arr[0] : arr[1]<arr[2] ? arr[1] : arr[2];
    for(int i=0; i<3; i++)
        if(arr[i] == min)
            return i;
}

//随机数产生函数 [low, high) 
double randval(double low, double high)  
{   
    double val;   
    val = ((double)(rand()%RAND_MAX)/(double)RAND_MAX)*(high - low) + low;   
    return val;   
}

//读入邻接矩阵,并转换为邻接表
void read()
{
    ifstream fin;
    fin.open("t1.txt");
    int i, j, g;
    for(i=0; i<N; i++)
    {
        for(j=0; j<N; j++)
        {
            fin >> g;    
            if(g == 1)
                G[i].push_back(j);
        }
    }
    fin.close();
}

void swap(int* p, int* q)
{
    int tmp = *p;
    *p = *q;
    *q = tmp;
}

void shuffle(int *arr, int n)
{
    int i;
    for(i=0; i<n; i++) 
    {
        int idx = rand() % (i + 1); //选取互换的位置
        swap(&arr[idx], &arr[i]);
    }
}

//种群初始化
void init()
{
    read();  //读入文件

    int num[N];
    int i, j;
    for(i=0; i<N; i++)
        num[i] = i;
    int conflict[3];   

    for(i=0; i<POPSIZE; i++) //产生POPSIZE个排列
    {
        shuffle(num, N);
        for(j=0; j<N; j++)
        {
            memset(conflict, 0, sizeof(conflict));
            int u = num[j];  //当前顶点
            for(int k=0; k<3; k++)  //第k个划分
            {
                for(int v=0; v<G[u].size(); v++)  //G[u][v]为当前顶点的邻接点
                    if(population[i].gen[k].count(G[u][v]))
                        conflict[k]++;
            }
            int min = minIndex(conflict);
            population[i].gen[min].insert(u);
        }
    }
    population[POPSIZE].fitness = N * N;
}

//取得每个个体的适应度 
void evaluate(void)  
{   
    for(int i=0; i<POPSIZE; i++)  
    {
        population[i].fitness = population[i].getFit();
    }
}

//保存遗传后的最佳个体
void keep_the_best()  
{   
    int mem;  
    cur_best = 0;  
    set<int>::iterator it;
    //保存最佳个体的索引 
    for (mem = 0; mem < POPSIZE; mem++)   
    {    
        if (population[mem].fitness < population[POPSIZE].fitness)    
        {
            cur_best = mem;       
            population[POPSIZE].fitness = population[mem].fitness;
        }
    }       
    //一旦找到种群的最佳个体就拷贝
    for(int i=0; i<3; i++)
    {
        population[POPSIZE].gen[i].clear();
        for(it=population[cur_best].gen[i].begin(); it!=population[cur_best].gen[i].end(); it++)
            population[POPSIZE].gen[i].insert(*it);
    }
} 

//杂交函数:选择两个个体杂交 
void crossover(void)  
{   
    int mem, one;    
    int first = 0;   
    double x;  
    for (mem = 0; mem < POPSIZE; ++mem)   
    {    
        x = randval(0, 1);    
        if (x < PXOVER)    
        {     
            ++first;     
            if (first % 2 == 0)   //mem与one杂交
            {
                Xover(one, mem);
            }
            else       
                one = mem;       
        }    
    }   
}   

//交叉 
void Xover(int one, int two)  
{  
    int i;
    set<int>::iterator it;
    Entity X;
    for(i=0; i<3; i++)
    {
        for(it=population[one].gen[i].begin(); it!=population[one].gen[i].end(); it++)
        {
            if(population[two].gen[i].count(*it))   //交集
            {
                X.gen[i].insert(*it); 
            }
        }
    }
    //将剩余顶点随机插入3个划分中
    for(i=0; i<N; i++)
    {
        if(!X.gen[0].count(i)  && !X.gen[1].count(i) && !X.gen[2].count(i))
        {
            double r = randval(0, 3);
            if(r<1)
                X.gen[0].insert(i);
            else if(r<2)
                X.gen[1].insert(i);
            else
                X.gen[2].insert(i);
        }
    }
    X.fitness = X.getFit();
    q.push(X);
}

//变异函数,随机选择某一个体,并改变其中某一顶点所属划分
void mutate(void)  
{  
    for (int i = 0; i < POPSIZE; i++)  
    {
        double r1 = randval(0, 1);   //随机选择变异个体
        if(r1 < PMUTATION)
        {
            int r2 = rand()%N;       //随机选择变异个体中的某个顶点
            int r3 = rand()%3;       //随机选择放到某个划分中
            for(int j=0; j<3; j++)
            {
                if(population[i].gen[j].count(r2))
                {
                    population[i].gen[j].erase(r2);
                    break;
                }
            }
            population[i].gen[r3].insert(r2);
        }

    }
}

//搜寻杰出个体函数:找出最好和最坏的个体。 
//如果某代的最好个体比前一代的最好个体要坏,那么后者将会取代当前种群的最坏个体 
void elitist()  
{   
    int i;   
    double best, worst;           //最好和最坏个体的适应度值 
    int best_index, worst_index;  //最好和最坏个体的索引 
    best = population[0].fitness;   
    worst = population[0].fitness;    
    for (i = 0; i < POPSIZE - 1; ++i)   
    {    
        if(population[i].fitness < population[i+1].fitness)    
        {     
            if (population[i].fitness <= best)      //fitness越小,说明冲突的边数越少,适应性越好
            {      
                best = population[i].fitness;      
                best_index = i;     
            }      
            if (population[i+1].fitness >= worst)     
            {       
                worst = population[i+1].fitness;      
                worst_index = i + 1;      
            }     
        }    
        else     
        {     
            if (population[i].fitness >= worst)     
            {      
                worst = population[i].fitness;       
                worst_index = i;      
            }      
            if (population[i+1].fitness <= best)     
            {       
                best = population[i+1].fitness;       
                best_index = i + 1;     
            }      
        }  
    }    
    //如果新种群中的最好个体比前一代的最好个体要强的话,那么就把新种群的最好个体拷贝出来。 
    //否则就用前一代的最好个体取代这次的最坏个体 ]
    set<int>::iterator it;
    if (best <= population[POPSIZE].fitness)   
    {
        for(int i=0; i<3; i++)
        {
            population[POPSIZE].gen[i].clear();
            for(it=population[best_index].gen[i].begin(); it!=population[best_index].gen[i].end(); it++)
                population[POPSIZE].gen[i].insert(*it);
        }
        population[POPSIZE].fitness = population[best_index].fitness;
    } 
    else    
    {
        for(int i=0; i<3; i++)
        {
            population[worst_index].gen[i].clear();
            for(it=population[POPSIZE].gen[i].begin(); it!=population[POPSIZE].gen[i].end(); it++)
                population[worst_index].gen[i].insert(*it);
        }
        population[worst_index].fitness = population[POPSIZE].fitness;
    }
} 

//选择函数,保证优秀的个体得以生存 
void select(void)  
{   
    int i;   
    for(i=0; i<POPSIZE; i++)
    {
        q.push(population[i]);
    }

    i = 0;
    while(i < POPSIZE)
    {
        Entity node = q.top();
        q.pop();
        double p = randval(0, 1);
        if(p < PSELECT)
        {
            population[i] = node;
        }
        i++;
    } 
    //清空优先队列
    while(!q.empty())
        q.pop();
} 

ofstream fout;
//报告模拟进展情况
void report()
{
    fout << "第" << generation << "代:";
    fout << "最优值为" << population[POPSIZE].fitness << endl;
}

int main()
{
    srand(time(NULL));
    fout.open("log.txt");
    generation = 0;
    init();   
    evaluate();         //评价函数,可以由用户自定义,该函数取得每个基因的适应度
    keep_the_best();    //保存每次遗传后的最佳基因
    cout << "进化中(1000代,大约4分钟)...:";
    while(generation < MAXGENS)   
    {    
        cout << generation << " ";
        generation++;    
        select();     //选择函数:用于最大化合并杰出模型的标准比例选择,保证最优秀的个体得以生存
        crossover();  //杂交函数:选择两个个体来杂交,这里用单点杂交 
        mutate();     //变异函数:被该函数选中后会使得某一变量被一个随机的值所取代 
        report();     //报告模拟进展情况
        evaluate();   //评价函数,可以由用户自定义,该函数取得每个基因的适应度
        elitist();    //搜寻杰出个体函数:找出最好和最坏的个体。如果某代的最好个体比前一代的最好个体要坏,那么后者将会取代当前种群的最坏个体 
    }         
    cout << "\n着色情况:" << endl;
    set<int>::iterator it;
    fout << "着色情况:" << endl;
    for(int i=0; i<3; i++)
    {
        for(it = population[POPSIZE].gen[i].begin(); it != population[POPSIZE].gen[i].end(); it++)
        {
            cout << (*it) << " ";
            fout << (*it) << " ";
            x[*it] = i+1;
        }
        cout << endl << endl;
        fout << endl << endl;
    }
    for(i=0; i<N; i++)
    cout << x[i] << " ";
    cout << endl;
    cout << "冲突边数:" << num() << endl;

    cout << "Time used = " << (double)clock()/CLOCKS_PER_SEC << "s\n";  //时间以秒为单位
    fout << "Time used = " << (double)clock()/CLOCKS_PER_SEC << "s\n";  //时间以秒为单位
    return 0;
}

《限制颜色数的图着色---遗传算法》

参考文献:
韩丽霞. 自然启发的优化算法及其应用研究[D]. 陕西:西安电子科技大学,2009.

    原文作者:遗传算法
    原文地址: https://blog.csdn.net/u012319493/article/details/60883141
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞