最小生成树问题

Python011

最小生成树问题,第1张

关于遗传算法解决最小生成树的问题。

这是prufer编码的代码:

#include <stdio.h>

#define END 0 // 结束

#define L_BRACKET 1 // 左括号

#define R_BRACKET 2 // 右括号

#define NUMBER 4 // 数

typedef struct _node

{

int value// 节点

int childs// 子节点数

struct _node *parent// 父节点

struct _node *first_child// 第一个孩子节点

struct _node *sibling// 下一个兄弟节点

}NODE

typedef struct _token

{

int type// 标记类型(左、右括号,数)

int value// 值(仅当类型为数时有效)

}TOKEN

typedef void (*FUNC)(NODE *)

static NODE *pSmallest = 0// 指向最小的叶子节点

/* 取下一个标记

input 输入串

pToken 用于返回取得的标记

返回值 取走下一个标记后的输入串

*/

char *GetNextToken(char *input,TOKEN *pToken)

{

char *p,ch

int value

pToken->type = END

/* 跳过空白 */

p = input

while ((ch = *p) &&ch != '(' &&ch != ')' &&!isdigit(ch))

p++

switch(ch)

{

case '(': pToken->type = L_BRACKETp++break

case ')': pToken->type = R_BRACKETp++break

default:

/* 识别数 */

if (isdigit(ch))

{

value = 0

while ((ch = *p) &&isdigit(ch))

{

value = 10 * value + (ch - '0')

p++

}

pToken->type = NUMBER

pToken->value = value

}

break

}

/* 根据是否到达串尾返回不同的值*/

return (*p == '\0' ? 0 : p)

}

/* 根据输入内容构造树

input 输入串

返回值 构造的树的根节点指针

*/

NODE *BuildTree(char *input)

{

char *p

TOKEN token

NODE *pCur,*pNew,*pRoot,*pLast

p = inputpCur = pLast = pRoot = 0

do

{

p = GetNextToken(p,&token)

switch(token.type)

{

case L_BRACKET:

break

case R_BRACKET:

/* 回到上一级 */

pLast = pCur

if (0 != pCur)

pCur = pCur->parent

break

case NUMBER:

pNew = (NODE *)malloc(sizeof(NODE))

memset(pNew,0,sizeof(NODE))

pNew->value = token.value

/*设定父兄节点 */

pNew->parent = pCur

if (0 != pLast)

{

pLast->sibling = pNew

pLast = pNew

}

if (0 != pCur)

{

if (0 == pCur->childs++)

pCur->first_child = pNew

}

else pRoot = pNew

p = GetNextToken(p,&token)

if (token.type == L_BRACKET)

{

pCur = pNew/*下一个符号是 (,表示此子树有孩子节点*/

pLast = 0

}

else if (token.type == R_BRACKET)

pLast = pNew/*下一个符号是 ),表示某子树结束了*/

break

}

}while (0 != p)

return pRoot

}

/* 先序遍历树,并调用指定函数对遍历到的节点进行处理

pRoot 树的根节点指针

func 用于对访问到的节点进行处理的函数

*/

void TravelTree(NODE *pRoot,FUNC func)

{

NODE *pCur

if (0 == pRoot) return

(*func)(pRoot)

pCur = pRoot->first_child

while (pCur)

{

TravelTree(pCur,func)

pCur = pCur->sibling

}

}

/* 判断指定节点是否是叶子节点(只有一条边相连的节点) */

int IsLeafNode(NODE *pNode)

{

return (0 != pNode &&(0 == pNode->childs &&0 != pNode->parent)

|| (1 == pNode->childs &&0 == pNode->parent))

}

/* 比较叶子节点值 */

void LeafValueCompare(NODE *pNode)

{

if (IsLeafNode(pNode))

if (0 == pSmallest) pSmallest = pNode

else if (pNode->value <pSmallest->value)

pSmallest = pNode

}

/* 从树中删除指定的叶子节点

pRoot 指向树根的指针

pNode 要删除的节点指针

返回值 新的根节点指针

*/

NODE *ReleaseLeafNode(NODE *pRoot,NODE *pNode)

{

NODE *pParent,*pSibling

if (0 == pNode->childs)

{

pParent = pNode->parent

if (pParent)

{

pSibling = pParent->first_child

if (pNode == pSibling)/*要删除的是父节点的第一个孩子*/

pParent->first_child = pNode->sibling

else

{

while (pSibling &&pSibling->sibling != pNode)

pSibling = pSibling->sibling

if (pSibling)

pSibling->sibling = pNode->sibling

}

pParent->childs--

}

free(pNode)

}

else/*根节点被删除*/

{

pRoot = pNode->first_child

pRoot->parent = 0

free(pNode)

}

return pRoot

}

void ReleaseTree(NODE *pRoot)

{

NODE *pCur,*pNext

if (pRoot)

{

pCur = pRoot->first_child

while (pCur)

{

pNext = pCur->sibling

ReleaseTree(pCur)

pCur = pNext

}

free(pRoot)

}

}

int main(int argc,char *argv[])

{

NODE *pRoot

char line[250]

int n

while (!feof(stdin))

{

line[0] = '\0'

gets(line)

pRoot = BuildTree(line)

n = 0

while (pRoot &&pRoot->childs != 0)

{

pSmallest = 0

TravelTree(pRoot,LeafValueCompare)// 遍历树

if (0 == pSmallest->childs)

printf(n++ ? " %d" : "%d",pSmallest->parent->value)

else

printf(n++ ? " %d" : "%d",pSmallest->first_child->value)

pRoot = ReleaseLeafNode(pRoot,pSmallest)

}

if (0 != pRoot)

{

printf("\n")

ReleaseTree(pRoot)

}

}

return 0

}

然后是遗传算法的实现:

/**************************************************************************/

/* This is a simple genetic algorithm implementation where the */

/* evaluation function takes positive values only and the */

/* fitness of an individual is the same as the value of the */

/* objective function */

/**************************************************************************/

#include <stdio.h>

#include <stdlib.h>

#include <math.h>

/* Change any of these parameters to match your needs */

#define POPSIZE 50 /* population size */

#define MAXGENS 1000 /* max. number of generations */

#define NVARS 3 /* no. of problem variables */

#define PXOVER 0.8 /* probability of crossover */

#define PMUTATION 0.15 /* probability of mutation */

#define TRUE 1

#define FALSE 0

int generation/* current generation no. */

int cur_best/* best individual */

FILE *galog/* an output file */

struct genotype /* genotype (GT), a member of the population */

{

double gene[NVARS]/* a string of variables */

double fitness/* GT's fitness */

double upper[NVARS]/* GT's variables upper bound */

double lower[NVARS]/* GT's variables lower bound */

double rfitness/* relative fitness */

double cfitness/* cumulative fitness */

}

struct genotype population[POPSIZE+1]/* population */

struct genotype newpopulation[POPSIZE+1]/* new population*/

/* replaces the */

/* old generation */

/* Declaration of procedures used by this genetic algorithm */

void initialize(void)

double randval(double, double)

void evaluate(void)

void keep_the_best(void)

void elitist(void)

void select(void)

void crossover(void)

void Xover(int,int)

void swap(double *, double *)

void mutate(void)

void report(void)

/***************************************************************/

/* Initialization function: Initializes the values of genes */

/* within the variables bounds. It also initializes (to zero) */

/* all fitness values for each member of the population. It */

/* reads upper and lower bounds of each variable from the */

/* input file `gadata.txt'. It randomly generates values */

/* between these bounds for each gene of each genotype in the */

/* population. The format of the input file `gadata.txt' is */

/* var1_lower_bound var1_upper bound */

/* var2_lower_bound var2_upper bound ... */

/***************************************************************/

void initialize(void)

{

FILE *infile

int i, j

double lbound, ubound

if ((infile = fopen("gadata.txt","r"))==NULL)

{

fprintf(galog,"\nCannot open input file!\n")

exit(1)

}

/* initialize variables within the bounds */

for (i = 0i <NVARSi++)

{

fscanf(infile, "%lf",&lbound)

fscanf(infile, "%lf",&ubound)

for (j = 0j <POPSIZEj++)

{

population[j].fitness = 0

population[j].rfitness = 0

population[j].cfitness = 0

population[j].lower[i] = lbound

population[j].upper[i]= ubound

population[j].gene[i] = randval(population[j].lower[i],

population[j].upper[i])

}

}

fclose(infile)

}

/***********************************************************/

/* Random value generator: Generates a value within bounds */

/***********************************************************/

double randval(double low, double high)

{

double val

val = ((double)(rand()%1000)/1000.0)*(high - low) + low

return(val)

}

/*************************************************************/

/* Evaluation function: This takes a user defined function. */

/* Each time this is changed, the code has to be recompiled. */

/* The current function is: x[1]^2-x[1]*x[2]+x[3] */

/*************************************************************/

void evaluate(void)

{

int mem

int i

double x[NVARS+1]

for (mem = 0mem <POPSIZEmem++)

{

for (i = 0i <NVARSi++)

x[i+1] = population[mem].gene[i]

population[mem].fitness = (x[1]*x[1]) - (x[1]*x[2]) + x[3]

}

}

/***************************************************************/

/* Keep_the_best function: This function keeps track of the */

/* best member of the population. Note that the last entry in */

/* the array Population holds a copy of the best individual */

/***************************************************************/

void keep_the_best()

{

int mem

int i

cur_best = 0/* stores the index of the best individual */

for (mem = 0mem <POPSIZEmem++)

{

if (population[mem].fitness >population[POPSIZE].fitness)

{

cur_best = mem

population[POPSIZE].fitness = population[mem].fitness

}

}

/* once the best member in the population is found, copy the genes */

for (i = 0i <NVARSi++)

population[POPSIZE].gene[i] = population[cur_best].gene[i]

}

/****************************************************************/

/* Elitist function: The best member of the previous generation */

/* is stored as the last in the array. If the best member of */

/* the current generation is worse then the best member of the */

/* previous generation, the latter one would replace the worst */

/* member of the current population */

/****************************************************************/

void elitist()

{

int i

double best, worst/* best and worst fitness values */

int best_mem, worst_mem/* indexes of the best and worst member */

best = population[0].fitness

worst = population[0].fitness

for (i = 0i <POPSIZE - 1++i)

{

if(population[i].fitness >population[i+1].fitness)

{

if (population[i].fitness >= best)

{

best = population[i].fitness

best_mem = i

}

if (population[i+1].fitness <= worst)

{

worst = population[i+1].fitness

worst_mem = i + 1

}

}

else

{

if (population[i].fitness <= worst)

{

worst = population[i].fitness

worst_mem = i

}

if (population[i+1].fitness >= best)

{

best = population[i+1].fitness

best_mem = i + 1

}

}

}

/* if best individual from the new population is better than */

/* the best individual from the previous population, then */

/* copy the best from the new populationelse replace the */

/* worst individual from the current population with the */

/* best one from the previous generation */

if (best >= population[POPSIZE].fitness)

{

for (i = 0i <NVARSi++)

population[POPSIZE].gene[i] = population[best_mem].gene[i]

population[POPSIZE].fitness = population[best_mem].fitness

}

else

{

for (i = 0i <NVARSi++)

population[worst_mem].gene[i] = population[POPSIZE].gene[i]

population[worst_mem].fitness = population[POPSIZE].fitness

}

}

/**************************************************************/

/* Selection function: Standard proportional selection for */

/* maximization problems incorporating elitist model - makes */

/* sure that the best member survives */

/**************************************************************/

void select(void)

{

int mem, i, j, k

double sum = 0

double p

/* find total fitness of the population */

for (mem = 0mem <POPSIZEmem++)

{

sum += population[mem].fitness

}

/* calculate relative fitness */

for (mem = 0mem <POPSIZEmem++)

{

population[mem].rfitness = population[mem].fitness/sum

}

population[0].cfitness = population[0].rfitness

/* calculate cumulative fitness */

for (mem = 1mem <POPSIZEmem++)

{

population[mem].cfitness = population[mem-1].cfitness +

population[mem].rfitness

}

/* finally select survivors using cumulative fitness. */

for (i = 0i <POPSIZEi++)

{

p = rand()%1000/1000.0

if (p <population[0].cfitness)

newpopulation[i] = population[0]

else

{

for (j = 0j <POPSIZEj++)

if (p >= population[j].cfitness &&

p<population[j+1].cfitness)

newpopulation[i] = population[j+1]

}

}

/* once a new population is created, copy it back */

for (i = 0i <POPSIZEi++)

population[i] = newpopulation[i]

}

/***************************************************************/

/* Crossover selection: selects two parents that take part in */

/* the crossover. Implements a single point crossover */

/***************************************************************/

void crossover(void)

{

int i, mem, one

int first = 0/* count of the number of members chosen */

double x

for (mem = 0mem <POPSIZE++mem)

{

x = rand()%1000/1000.0

if (x <PXOVER)

{

++first

if (first % 2 == 0)

Xover(one, mem)

else

one = mem

}

}

}

/**************************************************************/

/* Crossover: performs crossover of the two selected parents. */

/**************************************************************/

void Xover(int one, int two)

{

int i

int point/* crossover point */

/* select crossover point */

if(NVARS >1)

{

if(NVARS == 2)

point = 1

else

point = (rand() % (NVARS - 1)) + 1

for (i = 0i <pointi++)

swap(&population[one].gene[i], &population[two].gene[i])

}

}

/*************************************************************/

/* Swap: A swap procedure that helps in swapping 2 variables */

/*************************************************************/

void swap(double *x, double *y)

{

double temp

temp = *x

*x = *y

*y = temp

}

/**************************************************************/

/* Mutation: Random uniform mutation. A variable selected for */

/* mutation is replaced by a random value between lower and */

/* upper bounds of this variable */

/**************************************************************/

void mutate(void)

{

int i, j

double lbound, hbound

double x

for (i = 0i <POPSIZEi++)

for (j = 0j <NVARSj++)

{

x = rand()%1000/1000.0

if (x <PMUTATION)

{

/* find the bounds on the variable to be mutated */

lbound = population[i].lower[j]

hbound = population[i].upper[j]

population[i].gene[j] = randval(lbound, hbound)

}

}

}

/***************************************************************/

/* Report function: Reports progress of the simulation. Data */

/* dumped into the output file are separated by commas */

/***************************************************************/

void report(void)

{

int i

double best_val/* best population fitness */

double avg/* avg population fitness */

double stddev/* std. deviation of population fitness */

double sum_square/* sum of square for std. calc */

double square_sum/* square of sum for std. calc */

double sum/* total population fitness */

sum = 0.0

sum_square = 0.0

for (i = 0i <POPSIZEi++)

{

sum += population[i].fitness

sum_square += population[i].fitness * population[i].fitness

}

avg = sum/(double)POPSIZE

square_sum = avg * avg * POPSIZE

stddev = sqrt((sum_square - square_sum)/(POPSIZE - 1))

best_val = population[POPSIZE].fitness

fprintf(galog, "\n%5d, %6.3f, %6.3f, %6.3f \n\n", generation,

best_val, avg, stddev)

}

/**************************************************************/

/* Main function: Each generation involves selecting the best */

/* members, performing crossover &mutation and then */

/* evaluating the resulting population, until the terminating */

/* condition is satisfied */

/**************************************************************/

void main(void)

{

int i

if ((galog = fopen("galog.txt","w"))==NULL)

{

exit(1)

}

generation = 0

fprintf(galog, "\n generation best average standard \n")

fprintf(galog, " number value fitness deviation \n")

initialize()

evaluate()

keep_the_best()

while(generation<MAXGENS)

{

generation++

select()

crossover()

mutate()

report()

evaluate()

elitist()

}

fprintf(galog,"\n\n Simulation completed\n")

fprintf(galog,"\n Best member: \n")

for (i = 0i <NVARSi++)

{

fprintf (galog,"\n var(%d) = %3.3f",i,population[POPSIZE].gene[i])

}

fprintf(galog,"\n\n Best fitness = %3.3f",population[POPSIZE].fitness)

fclose(galog)

printf("Success\n")

}

/***************************************************************/

如何用此遗传算法解决最小生成树的问题呢,要求先随机初始化一个图,然后生成对应的最小生成树。

欢迎推荐小组话题,请先登录或注册

快速注册

你的email地址:

请填写email 用于确认你的身份, 豆瓣绝不会公开你的email。

给自己设一个密码:

请填写长度大于3的密码 你需要用它登录, 请使用英文字母、符号或数字。

给自己起一个名号:

起个名号吧 中、英文均可。

进化计算是基于自然选择和自然遗传等生物进化机制的一种搜索算法。与普通的搜索方法一样,进化计算也是一种迭代算法,不同的是进化计算在最优解的搜索过程中,一般是从原问题的一组解出发改进到另一组较好的解,再从这组改进的解出发进一步改进。而且在进化问题中,要求当原问题的优化模型建立后,还必须对原问题的解进行编码。进化计算在搜索过程中利用结构化和随机性的信息,使最满足目标的决策获得最大的生存可能,是一种概率型的算法。

一般来说,进化计算的求解包括以下几个步骤:给定一组初始解;评价当前这组解的性能;从当前这组解中选择一定数量的解作为迭代后的解的基础;再对其进行操作,得到迭代后的解;若这些解满足要求则停止,否则将这些迭代得到的解作为当前解重新操作。

以遗传算法为例,其工作步骤可概括为:

(1) 对工作对象——字符串用二进制的0/1或其它进制字符编码 。

(2) 根据字符串的长度L,随即产生L个字符组成初始个体

(3) 计算适应度。适应度是衡量个体优劣的标志,通常是所研究问题的目标函数。

(4) 通过复制,将优良个体插入下一代新群体中,体现“优胜劣汰”的原则。

(5) 交换字符,产生新个体。交换点的位置是随机决定的

(6) 对某个字符进行补运算,将字符1变为0,或将0变为1,这是产生新个体的另一种方法,突变字符的位置也是随机决定的。

(7) 遗传算法是一个反复迭代的过程,每次迭代期间,要执行适应度计算、复制、交换、突变等操作,直至满足终止条件。

将其用形式化语言表达,则为:假设α∈I记为个体,I记为个体空间。适应度函数记为Φ:I→R。在第t代,群体P(t)={a1(t),a2(t),…,an(t)}经过复制r(reproduction)、交换c(crossover)及突变m(mutation)转换成下一代群体。这里r、c、m均指宏算子,把旧群体变换为新群体。L:I→{True, Flase}记为终止准则。利用上述符号,遗传算法可描述为:

t=0

initialize P(0):={ a1(0),a2(0),…,an(0)}

while(l(P(t))≠True) do

evaluate P(t):{ Φ(a1(t)), Φ(a2(t)),…,Φ(an(t))}

reproduction: P′(t):=r(P(t))

crossover: P″(t):=c(P′(t))

mutation: P(t+1):= m(P″(t))

t=t+1

end