课设必备(求解TSP问题)(多种改进)

3 篇文章 0 订阅
3 篇文章 0 订阅

为了对付课设,启发式算法是一个划水的好帮手,特别是用启发式算法求解TSP问题,本文将利用遗传算法求解,听到是遗传算法觉得不咋地?别急,当你的改进足够多的时候,遗传算法都能玩出花来。

大家做课设,肯定是需要ppt的,为了便于大家划水,我将ppt的关键部分截图,大家各取所需。

研究背景

 关键技术

实践创新

重点!!!!!!!!

效果图

1原始遗传算法

2 改进1

3 改进2

4 改进3

5 改进4

6 改进5

7.蚁群算法

迭代对比

源码!!!!

#遗传算法求解TSP问题完整代码:
import copy
import time
from math import exp
import numpy as np
import matplotlib.pyplot as plt
import random
# 处理数据
coord = []
with open("data.txt", "r") as lines:
    lines = lines.readlines()
for line in lines:
    xy = line.split()
    coord.append(xy)
coord = np.array(coord)
w, h = coord.shape
coordinates = np.zeros((w, h), float)
for i in range(w):
    for j in range(h):
        coordinates[i, j] = float(coord[i, j])
# print(coordinates)
# 得到距离矩阵
distance = np.zeros((w, w))
for i in range(w):
    for j in range(w):
        distance[i, j] = distance[j, i] = np.linalg.norm(coordinates[i] - coordinates[j])
# 种群数
count = 300
# 进化次数
iter_time = 2000
# 最优选择概率
retain_rate = 0.3  # 适应度前30%可以活下来
# 弱者生存概率
random_select_rate = 0.5
# 变异
mutation_rate = 0.1
# 改良
gailiang_N = 2000
##按批选择
batch_size = 30   #################################################可以进行控制或者选择,最终选择最优的情况
# 适应度
CREATIVE = 0.1 ###在交叉或者遗传部分可能会利用信息素进行子个体的生成
CREATIVE_BAD = 0.5 ####有一定的概率会生成出适应度最差的个体

def variation_tools(list,point_1,point_2):
    ##确保point_1 < point_2
    if point_1 > point_2:
        cur = point_1
        point_1 = point_2
        point_2 = cur
    i = 0

    while(True):
        # print(point_1+i)
        cur = list[point_1+i]
        list[point_1+i] = list[point_2-i]
        list[point_2-i] = cur
        i+=1
        if (point_1+i) - (point_2-i) > 0:
            break
    return list
def get_total_distance(x):  ##获取x(一个可行解列表)
    dista = 0
    for i in range(len(x)):
        if i == len(x) - 1:
            dista += distance[x[i]][x[0]]
        else:
            dista += distance[x[i]][x[i + 1]]
    return dista
# 初始种群的改良
########################################进行优化,不仅仅是对于两个点进行交换,也可能对两个点之间的序列进行倒序排列,并且会有一定的概率接受次优解(效果差于之前的个体)
G1 = 0.1
def gailiang(x):
    distance = get_total_distance(x)    ##利用distance记录当前的解(x)的总距离
    gailiang_num = 0   #改良的数量
    while gailiang_num < gailiang_N:
        while True:
            a = random.randint(0, len(x) - 1)
            b = random.randint(0, len(x) - 1)
            if a != b:
                break
        if random.random() < G1:
            new_x = x.copy()
            new_x = variation_tools(new_x,a,b)
        else:
            new_x = x.copy()
            temp_a = new_x[a]
            new_x[a] = new_x[b]
            new_x[b] = temp_a
        if get_total_distance(new_x) < distance:
            x = new_x.copy()
            ######以一定的概率接受次优解
        elif random.random()<=(exp((get_total_distance(new_x)-distance) / gailiang_num)-1):
            x = new_x.copy()
        gailiang_num += 1
    return x
# 自然选择
def nature_select(population):
    grad = [[x, get_total_distance(x)] for x in population]
    grad = [x[0] for x in sorted(grad, key=lambda x: x[1])]
    # 强者
    retain_length = int(retain_rate * len(grad))
    parents = grad[: retain_length]
    # 生存下来的弱者
    for ruozhe in grad[retain_length:]:
        if random.random() < random_select_rate:
            parents.append(ruozhe)
    return parents
# 交叉繁殖
def crossover(parents):
    target_count = count - len(parents)
    children = []
    while len(children) < target_count:
        while True:
            male_index = random.randint(0, len(parents)-1)
            female_index = random.randint(0, len(parents)-1)
            if male_index != female_index:
                break
        male = parents[male_index]
        female = parents[female_index]
        left = random.randint(0, len(male) - 2)
        right = random.randint(left, len(male) - 1)
        gen_male = male[left:right]
        gen_female = female[left:right]
        child_a = []
        child_b = []
        len_ca = 0
        for g in male:
            if len_ca == left:
                child_a.extend(gen_female)
                len_ca += len(gen_female)
            if g not in gen_female:
                child_a.append(g)
                len_ca += 1
        len_cb = 0
        for g in female:
            if len_cb == left:
                child_b.extend(gen_male)
                len_cb += len(gen_male)
            if g not in gen_male:
                child_b.append(g)
                len_cb += 1

        children.append(child_a)
        children.append(child_b)
    return children
# 变异操作
def mutation(children):
    for i in range(len(children)):
        if random.random() < mutation_rate:
            while True:
                u = random.randint(0, len(children[i]) - 1)
                v = random.randint(0, len(children[i]) - 1)
                if u != v:
                    break
            if random.random() < G1:
                children[i] = variation_tools(children[i],u,v)
            else:
                temp_a = children[i][u]
                children[i][u] = children[i][v]
                children[i][v] = temp_a
    return children
def get_result(population):
    grad = [[x, get_total_distance(x)] for x in population]
    grad = sorted(grad, key=lambda x: x[1])
    return grad[0][0], grad[0][1]
###轮盘赌法
def random_way(P_IJ):  # 传入了转移概率,利用轮盘法进行选择  返回值为索引i----->选择的转移概率中的第n个点
    ran = random.random()
    # length = len(P_IJ[:, 0])
    length = len(P_IJ)
    t = [0]
    sum = 0
    for tem in range(0,length):
        sum += P_IJ[tem]
        # print(sum)
        t.append(sum)
    # print(t)
    for i in range(0,len(t)-1):
        # print(t[i])
        # print(ran)
        if t[i]<=ran and t[i+1] > ran:
            return i
def find_max(list):
    ##对于信息素进行归一化
    list1 = copy.deepcopy(list)
    s = sum(list1)
    for i in range(0,len(list1)):
        list1[i] = list1[i]/s
    ##归一化处理完毕
    return random_way(list1) ###返回最终结果---是一个索引(从0开始)
def find_min(list):
    list1 = copy.deepcopy(list)
    for i in range(0, len(list1)):
        if list1[i] != 0:
            list1[i] = 1/list1[i]
        else:
            list1[i] = 0.1
    s = sum(list1)
    for i in range(0,len(list1)):
        list1[i] = list1[i]/s
    return random_way(list1)
################################可以根据信息素浓度产生下一个解
def generate_init(pheromone):
    result = []
    result.append(random.randint(0,w-1))##确定了第一个点
    for i in range(1,w):##用来确定后续的点
        point_now = result[i-1]##确定当前点
        while(True):###确保找出来的点不在之前的路径中
            next_point = find_max(pheromone[point_now,:])
            if next_point not in result:
                break
        result.append(next_point)
    return result
def generate_init_bad(pheromone):  ###生成最差的个体
    result = []
    result.append(random.randint(0,w-1))##确定了第一个点
    for i in range(1,w):##用来确定后续的点
        point_now = result[i-1]##确定当前点
        while(True):###确保找出来的点不在之前的路径中
            next_point = find_min(pheromone[point_now,:])
            if next_point not in result:
                break
        result.append(next_point)
    return result
def new_pheromone(list,pheromone):
    pheromone = pheromone * (1 - 0.001)
    for i in list:
        fit = 1/get_total_distance(i)
        for kk in range(0,len(i)-1):
            pheromone[i[kk],i[kk+1]] += fit
            pheromone[i[kk+1], i[kk]] = pheromone[i[kk],i[kk+1]]
    return pheromone
def chuangxin(p1,parents):
    # print(parents)
    c1 = generate_init(p1)
    c2 = generate_init(p1)
    c3 = generate_init(p1)
    c4 = generate_init(p1)
    c5 = generate_init(p1)
    # grad = [[x, get_total_distance(x)] for x in population]
    # grad = [c1,get_total_distance(c1)]
    parents.append(c1)
    parents.append(c2)
    parents.append(c3)
    parents.append(c4)
    parents.append(c5)
    if random.random()<CREATIVE_BAD:
        c6 = generate_init_bad(p1)
        c7 = generate_init_bad(p1)
        c8 = generate_init_bad(p1)
        c9 = generate_init_bad(p1)
        c10 = generate_init_bad(p1)
        # grad = [[x, get_total_distance(x)] for x in population]
        # grad = [c1, get_total_distance(c2)]
        parents.append(c6)
        parents.append(c7)
        parents.append(c8)
        parents.append(c9)
        parents.append(c10)

    return parents
def run():
    pheromone = np.ones([w,w]) ##信息素浓度矩阵
    t1 = time.time()
    population = []
    # 初始化种群   +  改良阶段###############################
    index = [i for i in range(w)] ###创建一个最简单的矩阵,为后面随机生成路径提供了基础
    t2 = time.time()
    G2 = 0.2###利用信息素产生解的概率
    for i in range(count): ##count
        if i<batch_size or random.random()<G2:
            x = index.copy()
            random.shuffle(x)
            x = gailiang(x)###改进
            # gailiang(x)  ###改进
            population.append(x)
        else:####根据信息素浓度产生
            x = generate_init(pheromone)
            ###可以对x再进行一些处理,暂时先空着
            population.append(x)
        if i%batch_size == 0:
            cur_p = population[i-20:i] ##进行切片操作,用来进行信息素的更新c  ###重点
            ###进行信息素的更新
            pheromone = new_pheromone(cur_p,pheromone)
    t3 = time.time()
    print("改良所花费的时间为:",t3-t2)
    #######################################################################
    distance_list = []
    result_cur_best, dist_cur_best = get_result(population)  #第一个为序列,第二个为距离
    distance_list.append(dist_cur_best)
    i = 0
    while i < iter_time:
        # 自然选择
        parents = nature_select(population)
        ####有一定的概率会利用信息素进行个体的生成 , 有可能会生成最好的个体,也可能会生成最差的个体(逃离死区)
        ##对于生成出的个体,直接加入到parents中即可
        if random.random() < CREATIVE:
            parents = chuangxin(pheromone,parents)##注意返回值
        # 繁殖
        children = crossover(parents)
        # 变异
        mutation(children)
        # 更新
        population = parents + children
        result_cur_best, dist_cur_best = get_result(population)
        distance_list.append(dist_cur_best)
        i = i + 1
        if i % 50 == 0:  ###对信息素进行更新
            # print("更新一次")
            pheromone = new_pheromone(population, pheromone)
        # print(result_cur_best)
        # print(dist_cur_best)
    for i in range(len(result_cur_best)):
        result_cur_best[i] += 1
    result_path = result_cur_best
    result_path.append(result_path[0])
    return dist_cur_best



if __name__ == '__main__':
    pheromone = np.ones([w, w])  ##信息素浓度矩阵
    t1 = time.time()
    population = []
    # 初始化种群   +  改良阶段###############################
    index = [i for i in range(w)]  ###创建一个最简单的矩阵,为后面随机生成路径提供了基础
    t2 = time.time()
    G2 = 0.2  ###利用信息素产生解的概率
    for i in range(count):  ##count
        if i < batch_size or random.random() < G2:
            x = index.copy()
            random.shuffle(x)
            x = gailiang(x)  ###改进
            # gailiang(x)  ###改进
            population.append(x)
        else:  ####根据信息素浓度产生
            x = generate_init(pheromone)
            ###可以对x再进行一些处理,暂时先空着
            population.append(x)
        if i % batch_size == 0:
            cur_p = population[i - 20:i]  ##进行切片操作,用来进行信息素的更新c  ###重点
            ###进行信息素的更新
            pheromone = new_pheromone(cur_p, pheromone)
    t3 = time.time()
    print("改良所花费的时间为:", t3 - t2)
    #######################################################################
    distance_list = []
    result_cur_best, dist_cur_best = get_result(population)  # 第一个为序列,第二个为距离
    distance_list.append(dist_cur_best)
    i = 0
    while i < iter_time:
        # 自然选择
        parents = nature_select(population)
        ####有一定的概率会利用信息素进行个体的生成 , 有可能会生成最好的个体,也可能会生成最差的个体(逃离死区)
        ##对于生成出的个体,直接加入到parents中即可
        if random.random() < CREATIVE:
            parents = chuangxin(pheromone, parents)  ##注意返回值
        # 繁殖
        children = crossover(parents)
        # 变异
        children = mutation(children)
        # 更新
        population = parents + children
        result_cur_best, dist_cur_best = get_result(population)
        distance_list.append(dist_cur_best)
        i = i + 1
        if i % 50 == 0:  ###对信息素进行更新
            # print("更新一次")
            pheromone = new_pheromone(population, pheromone)
        # print(result_cur_best)
        # print(dist_cur_best)
    for i in range(len(result_cur_best)):
        result_cur_best[i] += 1
    result_path = result_cur_best
    result_path.append(result_path[0])
    t4 = time.time()
    print()
    print("最佳路径为:", result_path)
    print("最短的长度为:", dist_cur_best)
    print("花费时间:",t4-t1)
    # 画图
    X = []
    Y = []
    for index in result_path:
        X.append(coordinates[index - 1, 0])
        Y.append(coordinates[index - 1, 1])

    plt.rcParams['font.sans-serif'] = 'SimHei'  # 设置中文显示
    plt.rcParams['axes.unicode_minus'] = False
    plt.figure("改进算法轨迹图")
    plt.plot(X, Y, '-o')
    for i in range(len(X)):
        plt.text(X[i] + 0.05, Y[i] + 0.05, str(result_path[i]), color='red')
    plt.xlabel('横坐标')
    plt.ylabel('纵坐标')
    plt.title('轨迹图')
    plt.savefig("路径图.png")
    plt.figure("改进算法迭代图")

    plt.plot(np.array(distance_list))
    plt.title('优化过程')
    plt.ylabel('最优值')
    plt.xlabel('代数({}->{})'.format(0, iter_time))
    plt.savefig("迭代过程图.png")
    plt.show()

直接就可以运行了,算法在当前目录下还需要data.txt文件,其中的数据为:

1.3 2.3
3.6 1.35
4.17 2.24
3.7 1.4
3.4 1.5
3.3 1.56
3.2 1.2
4.2 1.08
4.3 0.8
4.4 0.6
3.0 2.0
2.56 1.75
2.78 1.49
2.38 1.67
1.332 0.695
3.715 1.678
3.918 2.179
4.061 2.37
3.78 2.212
3.676 2.578
4.029 2.838
4.263 2.931
3.429 1.908
3.507 2.376
3.394 2.643
2.33 2.55
0.12 2.67
1.75 2.35
3.23 0.66
3.46 2.75
2.44 0.78
2.34 1.75
0.53 0.6
0.78 1.41
1.39 1.45
1.49 2.10
1.03 2.99
0.59 2.21
0.12 2.32
0.162 0.667
0.248 1.179
1.2 1.87
1.48 2.85
3.7 0.98
1.82 0.97
1.73 2.97
4.2 1.7
3.82 0.87
1.918 0.667
1.074 1.179
1.738 1.364
2.118 2
0.38 2.95
0.305 0.777
1.928 1.969
4.5 1.428
1.804 2.65
3.4 2.1
2.7 2.28
0.979 2.065

可自行增加和删除,每一行代表了一个点的横纵坐标,中间以空格作为分割。

致歉!

由于本人的疏忽,代码比较乱,很多改进的算法不知道放哪去了,所以只给出了最后的改进算法,如果你是为了课设,可以直接说出一个改进(最后这个),然后把本文的步骤随便删掉几个作为原始的遗传算法进行比较即可。

  • 17
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

主打一个实用

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值