基于星雀(Nutcracker)和麻雀(Sparrow)算法的物流配送路径规划问题求解程序

想和大神交朋友或想软件开发兼职接项目,请通过手机端搜小#程#序: "黄页小艺" 。

python 复制代码
# %%
import folium
import random
import numpy as np
from tqdm import tqdm
from copy import deepcopy
from random import randint
import matplotlib.pyplot as plt
from geopy.distance import geodesic
#
# # %%
# pip install geopy
#
# # %%
# 需求点数量
demand_point_num=20

# 供应点数量
supply_point_num=3

# 冷库集合
cold_storage_num=5

# 节点总数
point_num=demand_point_num+supply_point_num+cold_storage_num

# 产品种类
product_type=3

# 车辆数
vehicle_num=8

# 需求矩阵
demand_matrix={}
for d in range(demand_point_num):
    for p in range(product_type):
        demand_matrix[d,p]=randint(10,100)
        
# 时间窗
time_window={}
for d in range(demand_point_num):
    t1,t2,t=randint(0,100),randint(0,100),randint(1,10)
    ET,LT=min(t1,t2),max(t1,t2)
    time_window[d]=(ET,LT,t)
    
# 车辆的容量
vehicle_capacity={}
for v in range(vehicle_num):
    vehicle_capacity[v]=[]
    for p in range(product_type):
        vehicle_capacity[v].append(randint(200,500))
        
# 车辆的承重和体积
vehicle_weight={}
vehicle_volume={}
for v in range(vehicle_num):
    vehicle_weight[v]=randint(500,1000)
    vehicle_volume[v]=randint(500,1000)
    
# 车辆的运行速度/最远行驶距离
vehicle_speed={}
vehicle_distance={}
for v in range(vehicle_num):
    vehicle_speed[v]=randint(20,30)
    vehicle_distance=randint(100000,200000)

# 车辆的固定/单位成本
vehicle_fix_cost={}
vehicle_unit_cost={}
for v in range(vehicle_num):
    vehicle_fix_cost[v]=randint(1000,2000)
    vehicle_unit_cost[v]=randint(5,10)/1e4
    
# 车辆早到/晚到的惩罚成本
a1,a2=10,10
    
# 产品的重量和体积
product_weight={}
product_volume={}
for p in range(product_type):
    product_weight[p]=randint(1,5)
    product_volume[p]=randint(1,5)
    
# 冷库的建设成本
cold_storage_fix_cost={}
for c in range(cold_storage_num):
    cold_storage_fix_cost[c]=randint(1000000,3000000)

# 产品的重量/体积
product_weight={}
product_volume={}
for p in range(product_type):
    product_weight[p]=randint(1,5)
    product_volume[p]=randint(1,5)
    
# 节点坐标
node_point={}
for p in range(point_num):
    lat=randint(30421,30425)/1000
    lon=randint(120510,120530)/1000
    node_point[p]=(lat,lon)
    
# 距离矩阵
distance_matrix={}
for p1 in range(point_num):
    for p2 in range(point_num):
        distance=geodesic(node_point[p1],node_point[p2]).m
        distance_matrix[p1,p2]=distance


# %%
'''
整数转二进制
'''
def toBit(num,length):
    bit=[]
    for i in range(length-1,-1,-1):
        bit.append(int(num/(supply_point_num+cold_storage_num)**i))
        num-=bit[-1]*(supply_point_num+cold_storage_num)**i
    return bit

'''
星雀个体
'''
class Nutcracker:
    def __init__(self,individual):
        self.individual=individual
        self.result=self.decode()
        self.fitness=self.get_fitness()
        
    def decode(self):
        result={}
        bit=toBit(self.individual[0],vehicle_num)
        demand=deepcopy(demand_matrix)
        for i in self.individual[1]:
            result[i]={}
            serve_order=self.individual[2+i]
            capacity=deepcopy(vehicle_capacity[i])
            # 计算开始时间
            cur_time=distance_matrix[0,bit[i]]/vehicle_speed[i]
            cur_point=bit[i]
            result[i][cur_point]={}
            result[i][cur_point]['serve']={0:0,1:0,2:0}
            result[i][cur_point]['time']={'t1':cur_time,'t2':cur_time,'t3':cur_time}
            
            
            
            for j in serve_order:
                jj=j+supply_point_num+cold_storage_num
                
                # 车辆没有剩余容量
                if sum(capacity)==0:
                    break
                    
                # 需求点没有剩余需求
                if sum([demand[j,p] for p in range(product_type)])==0:
                    continue
                
                result[i][j]={}
                # 计算需求量
                result[i][j]['serve']={}
                for p in range(product_type):
                    min_num=min(demand[j,p],capacity[p])
                    demand[j,p]-=min_num
                    capacity[p]-=min_num
                    result[i][j]['serve'][p]=min_num
                    
                # 计算时间
                arrive_time=cur_time+distance_matrix[cur_point,jj]/vehicle_speed[i]
                satrt_serve_time=max(arrive_time,time_window[j][0])
                departure_time=satrt_serve_time+time_window[j][2]
                result[i][j]['time']={'t1':arrive_time,'t2':satrt_serve_time,'t3':departure_time}
                cur_time=departure_time
                cur_point=j
                
        return result
                
        
    def get_fitness(self):
        fitness=0
        self.result=self.decode()
        # 冷库建设成本
        bit=toBit(self.individual[0],vehicle_num)
        cold_set=set()
        for b in bit:
            if b>=supply_point_num:
                cold_set.add(b-supply_point_num)
        fitness+=sum([cold_storage_fix_cost[c] for c in cold_set])/(5*365)

        # 车辆运输成本 
        for i in self.result:
            if self.result[i]:
                fitness+=vehicle_fix_cost[i]
            cur_point=bit[i]
            for j in self.result[i]:
                jj=j+supply_point_num+cold_storage_num
                fitness+=vehicle_unit_cost[i]*distance_matrix[cur_point,jj]
                cur_point=jj
        

        # 需求延误成本
        for j in range(demand_point_num):
            min_arrive_time=1e8
            max_arrive_time=0
            for i in self.result:
                if j in self.result[i]:
                    min_arrive_time=min(min_arrive_time,self.result[i][j]['time']['t1'])
                    max_arrive_time=max(max_arrive_time,self.result[i][j]['time']['t1'])
            fitness+=a1*max(0,time_window[j][0]-min_arrive_time)
            fitness+=a2*max(0,max_arrive_time-time_window[j][1])

        self.fitness=1/fitness
        return 1/fitness

    
'''
生成个体
'''
def gen_nutcracker():
    num=randint(0,(supply_point_num+cold_storage_num)**vehicle_num-1)
    vehicle_order=[i for i in range(vehicle_num)]
    random.shuffle(vehicle_order)
    serve_order=[]
    for i in range(vehicle_num):
        cur_order=[j for j in range(demand_point_num)]
        random.shuffle(cur_order)
        serve_order.append(cur_order)
    individual=[num]+[vehicle_order]+serve_order
    nutcracker=Nutcracker(individual)
    return nutcracker


'''
生成种群
'''
def get_population(num):
    population=[]
    for i in range(num):
        population.append(gen_nutcracker())
    return population
        
'''
获取最优个体
'''
def get_best_nutcracker(population):
    best_fitness=0
    best_nutcracker=None
    for nutcracker in population:
        fitness=nutcracker.get_fitness()
        if fitness>best_fitness:
            best_fitness=fitness
            best_nutcracker=nutcracker
    return best_nutcracker
    
    
        
'''
觅食阶段
'''
def forage(nutcracker,population):
    # 随机探索
    if random.random()<exploring_probability:
        individual=nutcracker.individual
        individual[0]=randint(0,(supply_point_num+cold_storage_num)**vehicle_num-1)
        nutcracker=Nutcracker(individual)
        return nutcracker
    
    # 最优探索
    else:
        best_nutcracker=get_best_nutcracker(population)
        individual=nutcracker.individual
        best_individual=best_nutcracker.individual
        individual[0]=best_individual[0]
        nutcracker=Nutcracker(individual)
        return nutcracker
    
    
'''
储存阶段
'''
def store(nutcracker,best_population):
    new_best_population=deepcopy(best_population)
    new_best_population.append(nutcracker)
    new_best_population=sorted(new_best_population, key=lambda x: x.get_fitness())
    return new_best_population[1:]


'''
Levy飞行距离
'''
def levy_distance(nutcracker1,nutcracker2):
    individual1=nutcracker1.individual
    individual2=nutcracker2.individual
    
    distance=abs(individual1[0]-individual2[0])/max(individual1[0],individual2[0])
    
    for i in range(vehicle_num+1):
        ii=i+1
        
        sum1=0
        for j in range(len(individual1[ii])):
            sum1+=j*individual1[ii][j]
        
        sum2=0
        for j in range(len(individual2[ii])):
            sum2+=j*individual2[ii][j]
            
        distance+=abs(sum1-sum2)/max(sum1,sum2)
        
    return distance
        
            
    
'''
缓存搜索阶段
'''
def search(nutcracker,best_population):
    individual=nutcracker.individual
    for cur_nutcracker in best_population:
        if levy_distance(nutcracker,cur_nutcracker)>distance:
            continue
        cur_individual=cur_nutcracker.individual
        new_individual=[]
        for i in range(len(individual)):
            if randint(0,1):
                new_individual.append(individual[i])
            else:
                new_individual.append(cur_individual[i])
        new_nutcracker=Nutcracker(new_individual)
        if new_nutcracker.get_fitness()>nutcracker.get_fitness():
            nutcracker=deepcopy(new_nutcracker)
    return nutcracker


def swap(nutcracker):
    individual=deepcopy(nutcracker.individual)
    for i in range(len(individual[1])):
        for j in range(i+1,len(individual[1])):
            individual[1][i],individual[1][j]=individual[1][j],individual[1][i]
            new_nutcracker=Nutcracker(individual)
            if nutcracker.get_fitness()>new_nutcracker.get_fitness():
                individual[1][i],individual[1][j]=individual[1][j],individual[1][i]
    return Nutcracker(individual)
    
    

def new_search(nutcracker,best_population):
    individual=nutcracker.individual
    for cur_nutcracker in best_population:
        if levy_distance(nutcracker,cur_nutcracker)>distance:
            continue
        cur_individual=cur_nutcracker.individual
        new_individual=[]
        for i in range(len(individual)):
            if randint(0,1):
                new_individual.append(individual[i])
            else:
                new_individual.append(cur_individual[i])
        new_nutcracker=Nutcracker(new_individual)
        if new_nutcracker.get_fitness()>nutcracker.get_fitness():
            nutcracker=deepcopy(new_nutcracker)
    return swap(nutcracker)

# %%
'''
绘制收敛图
'''
def plot_convergence(convergence_records):
    num_curves = len(convergence_records)  
    
    for i in range(num_curves):
        cur=convergence_records[i]
        convergence_records[i]=[1/i for i in cur]
    
    colors = ['b', 'g', 'r', 'c', 'm', 'y', 'k', 'w']  

    plt.figure(figsize=(20, 10))

    for i, record in enumerate(convergence_records):
        iterations = list(range(1, len(record) + 1))
        plt.plot(iterations, record, marker='o', label=f'Curve {i+1}', color=colors[i % len(colors)])

    plt.title('Convergence Plots')  
    plt.xlabel('Iteration') 
    plt.ylabel('Cost')  
    plt.legend()
    plt.grid(False)  
    plt.show()

    
'''
绘制路线图
'''
def plot_locations(m,locations,color):
    locations.append(locations[0])
    folium.PolyLine(locations, color=color, weight=2.5, opacity=1).add_to(m)
    for i, (lat, lon) in enumerate(locations):
        color='blue'
        for k in node_point:
            point=(lat, lon)
            if point==node_point[k]:
                if k<supply_point_num:
                    color='red'
                elif k<supply_point_num+cold_storage_num:
                    color='green'
        folium.Marker([lat, lon], popup=f'Location {i+1}',icon=folium.Icon(color=color)).add_to(m)
    return m


def plot_route(nutcracker):
    m = folium.Map(location=node_point[0], zoom_start=13,tiles='http://webrd02.is.autonavi.com/appmaptile?lang=zh_en&size=1&scale=1&style=8&x={x}&y={y}&z={z}', attr='高德-中英文对照')

    color_list = [
        'red', 'blue', 'green', 'purple', 'orange',
        'darkred', 'lightred', 'beige', 'darkblue', 'darkgreen',
        'cadetblue', 'darkpurple', 'white', 'pink', 'lightblue',
        'lightgreen', 'gray', 'black', 'lightgray'
    ]

    cnt=0
    for v in best_nutcracker.result:
        locations=[]
        if not best_nutcracker.result[v]:
            continue
        for p in nutcracker.result[v]:
            locations.append(node_point[p])
        m=plot_locations(m,locations,color_list[cnt])
        cnt+=1
    return m

# %%
# ### 基础算法

# In[4]:


# 种群数量
population_num=20

# 储存数量
store_num=5

# 迭代次数
iteration_num=100

# 探索概率
exploring_probability=0.5

# 飞行距离
distance=2

# 生成初始种群
population=get_population(population_num)

# 最优个体
best_nutcracker=get_best_nutcracker(population)

# 迭代求解
record=[best_nutcracker.get_fitness()]
best_population=sorted(population, key=lambda x: x.get_fitness())[-store_num:]
for it in tqdm(range(iteration_num)):
    for i in range(len(population)):
        nutcracker=population[i]
        
        # 觅食阶段
        nutcracker=forage(nutcracker,population)
        
        # 储存阶段
        best_population=store(nutcracker,best_population)
        
        # 缓存搜索阶段
        nutcracker=search(nutcracker,best_population)
        
        # 更新个体
        population[i]=nutcracker
        
        # 更新最优个体
        if nutcracker.get_fitness()>best_nutcracker.get_fitness():
            best_nutcracker=deepcopy(nutcracker)
    record.append(best_nutcracker.get_fitness())
    
plot_convergence([record])
m=plot_route(best_nutcracker)
m.save('basis.html')

# %%
# ### 改进算法

# In[5]:


# 种群数量
population_num=20

# 储存数量
store_num=5

# 迭代次数
iteration_num=100

# 探索概率
exploring_probability=0.5

# 飞行距离
distance=2

# 生成初始种群
population=get_population(population_num)

# 最优个体
best_nutcracker=get_best_nutcracker(population)

# 迭代求解
record1=[best_nutcracker.fitness]
best_population=sorted(population, key=lambda x: x.fitness)[-store_num:]
for it in tqdm(range(iteration_num)):
    for i in range(len(population)):
        nutcracker=population[i]
        
        # 觅食阶段
        new_nutcracker=forage(nutcracker,population)
        dert_fitness=new_nutcracker.get_fitness()-nutcracker.get_fitness()
        if dert_fitness>0 or random.random()<np.exp(dert_fitness/(it+1)):
            nutcracker=deepcopy(new_nutcracker)
        
        
        
        # 储存阶段
        best_population=store(nutcracker,best_population)
        
        # 缓存搜索阶段
        nutcracker=new_search(nutcracker,best_population)
        
        # 更新个体
        population[i]=nutcracker
        
        # 更新最优个体
        if nutcracker.fitness>best_nutcracker.fitness:
            best_nutcracker=deepcopy(nutcracker)
    record1.append(best_nutcracker.fitness)
    
plot_convergence([record1])
m=plot_route(best_nutcracker)
m.save('improve.html')

# %%
# 整数转二进制
def toBit(num, length):
    bit = []
    for i in range(length - 1, -1, -1):
        bit.append(int(num / (supply_point_num + cold_storage_num) ** i))
        num -= bit[-1] * (supply_point_num + cold_storage_num) ** i
    return bit

# 麻雀个体
class Sparrow:
    def __init__(self, individual):
        self.individual = individual
        self.fitness = self.get_fitness()
        
    def get_fitness(self):
        fitness = 0
        result = self.decode()
        # 冷库建设成本
        bit = toBit(self.individual[0], vehicle_num)
        cold_set = set()
        for b in bit:
            if b >= supply_point_num:
                cold_set.add(b - supply_point_num)
        fitness += sum([cold_storage_fix_cost[c] for c in cold_set]) / (5 * 365)

        # 车辆运输成本 
        for i in result:
            if result[i]:
                fitness += vehicle_fix_cost[i]
            cur_point = bit[i]
            for j in result[i]:
                jj = j + supply_point_num + cold_storage_num
                fitness += vehicle_unit_cost[i] * distance_matrix[cur_point, jj]
                cur_point = jj

        # 需求延误成本
        for j in range(demand_point_num):
            min_arrive_time = 1e8
            max_arrive_time = 0
            for i in result:
                if j in result[i]:
                    min_arrive_time = min(min_arrive_time, result[i][j]['time']['t1'])
                    max_arrive_time = max(max_arrive_time, result[i][j]['time']['t1'])
            fitness += a1 * max(0, time_window[j][0] - min_arrive_time)
            fitness += a2 * max(0, max_arrive_time - time_window[j][1])

        self.fitness = 1 / fitness
        return 1 / fitness
    
    def decode(self):
        result = {}
        bit = toBit(self.individual[0], vehicle_num)
        demand = deepcopy(demand_matrix)
        for i in self.individual[1]:
            result[i] = {}
            serve_order = self.individual[2 + i]
            capacity = deepcopy(vehicle_capacity[i])
            # 计算开始时间
            cur_time = distance_matrix[0, bit[i]] / vehicle_speed[i]
            cur_point = bit[i]
            result[i][cur_point] = {}
            result[i][cur_point]['serve'] = {0: 0, 1: 0, 2: 0}
            result[i][cur_point]['time'] = {'t1': cur_time, 't2': cur_time, 't3': cur_time}
            
            for j in serve_order:
                jj = j + supply_point_num + cold_storage_num
                
                # 车辆没有剩余容量
                if sum(capacity) == 0:
                    break
                
                # 需求点没有剩余需求
                if sum([demand[j, p] for p in range(product_type)]) == 0:
                    continue
                
                result[i][j] = {}
                # 计算需求量
                result[i][j]['serve'] = {}
                for p in range(product_type):
                    min_num = min(demand[j, p], capacity[p])
                    demand[j, p] -= min_num
                    capacity[p] -= min_num
                    result[i][j]['serve'][p] = min_num
                    
                # 计算时间
                arrive_time = cur_time + distance_matrix[cur_point, jj] / vehicle_speed[i]
                satrt_serve_time = max(arrive_time, time_window[j][0])
                departure_time = satrt_serve_time + time_window[j][2]
                result[i][j]['time'] = {'t1': arrive_time, 't2': satrt_serve_time, 't3': departure_time}
                cur_time = departure_time
                cur_point = j
                
        return result

# 生成个体
def gen_sparrow():
    num = randint(0, (supply_point_num + cold_storage_num) ** vehicle_num - 1)
    vehicle_order = [i for i in range(vehicle_num)]
    random.shuffle(vehicle_order)
    serve_order = []
    for i in range(vehicle_num):
        cur_order = [j for j in range(demand_point_num)]
        random.shuffle(cur_order)
        serve_order.append(cur_order)
    individual = [num] + [vehicle_order] + serve_order
    sparrow = Sparrow(individual)
    return sparrow

# 生成种群
def get_population(num):
    population = []
    for i in range(num):
        population.append(gen_sparrow())
    return population

# 获取最优个体
def get_best_sparrow(population):
    best_fitness = float('inf')
    best_sparrow = None
    for sparrow in population:
        if sparrow.fitness < best_fitness:
            best_fitness = sparrow.fitness
            best_sparrow = sparrow
    return best_sparrow
# 混沌序列生成器(Logistic映射)
def logistic_map(x, r=3.99):
    return r * x * (1 - x)

# 混沌初始化种群
def chaos_initialize_sparrows(population_size):
    population = []
    x = 0.5  # 初始值
    for _ in range(population_size):
        individual = []
        for _ in range(vehicle_num):
            x = logistic_map(x)
            num = int(x * ((supply_point_num + cold_storage_num) ** vehicle_num))
            vehicle_order = [i for i in range(vehicle_num)]
            random.shuffle(vehicle_order)
            serve_order = []
            for i in range(vehicle_num):
                cur_order = [j for j in range(demand_point_num)]
                random.shuffle(cur_order)
                serve_order.append(cur_order)
            individual = [num] + [vehicle_order] + serve_order
        population.append(Sparrow(individual))
    return population
# 觅食阶段
def forage(sparrow, population):
    # 随机探索
    if random.random() < exploring_probability:
        individual = sparrow.individual
        individual[0] = randint(0, (supply_point_num + cold_storage_num) ** vehicle_num - 1)
        sparrow = Sparrow(individual)
        return sparrow
    
    # 最优探索
    else:
        best_sparrow = get_best_sparrow(population)
        individual = sparrow.individual
        best_individual = best_sparrow.individual
        individual[0] = best_individual[0]
        sparrow = Sparrow(individual)
        return sparrow

# 储存阶段
def store(sparrow, best_population):
    new_best_population = deepcopy(best_population)
    new_best_population.append(sparrow)
    new_best_population = sorted(new_best_population, key=lambda x: x.fitness)
    return new_best_population[1:]

# Levy飞行距离
def levy_distance(nutcracker1, nutcracker2):
    individual1 = nutcracker1.individual
    individual2 = nutcracker2.individual
    
    distance = abs(individual1[0] - individual2[0]) / max(individual1[0], individual2[0])
    
    for i in range(vehicle_num + 1):
        ii = i + 1
        
        sum1 = 0
        for j in range(len(individual1[ii])):
            sum1 += j * individual1[ii][j]
        
        sum2 = 0
        for j in range(len(individual2[ii])):
            sum2 += j * individual2[ii][j]
            
        distance += abs(sum1 - sum2) / max(sum1, sum2)
        
    return distance
        
    
# 缓存搜索阶段
def search(sparrow, best_population):
    individual = sparrow.individual
    for cur_sparrow in best_population:
        if levy_distance(sparrow, cur_sparrow) > distance:
            continue
        cur_individual = cur_sparrow.individual
        new_individual = []
        for i in range(len(individual)):
            if randint(0, 1):
                new_individual.append(individual[i])
            else:
                new_individual.append(cur_individual[i])
        new_sparrow = Sparrow(new_individual)
        if new_sparrow.fitness > sparrow.fitness:
            sparrow = deepcopy(new_sparrow)
    return sparrow

# 绘制收敛图
def plot_convergence(convergence_records):
    num_curves = len(convergence_records)  
    
    for i in range(num_curves):
        cur = convergence_records[i]
        convergence_records[i] = [1 / i for i in cur]
    
    colors = ['b', 'g', 'r', 'c', 'm', 'y', 'k', 'w']  

    plt.figure(figsize=(20, 10))

    for i, record in enumerate(convergence_records):
        iterations = list(range(1, len(record) + 1))
        plt.plot(iterations, record, marker='o', label=f'Curve {i+1}', color=colors[i % len(colors)])

    plt.title('Convergence Plots')  
    plt.xlabel('Iteration') 
    plt.ylabel('Cost')  
    plt.legend()
    plt.grid(False)  
    plt.show()


# %%
# 种群数量
population_num=20

# 储存数量
store_num=5

# 迭代次数
iteration_num=100

# 探索概率
exploring_probability=0.5

# 飞行距离
distance=2

# 生成初始种群
population=get_population(population_num)

# 最优个体
best_sparrow = get_best_sparrow(population)

# 迭代求解
record2 = [best_sparrow.fitness]
best_population = sorted(population, key=lambda x: x.fitness)[-store_num:]
for it in tqdm(range(iteration_num)):
    for i in range(len(population)):
        sparrow = population[i]
        # 觅食阶段
        sparrow = forage(sparrow, population)
        # 储存阶段
        best_population = store(sparrow, best_population)
        # 缓存搜索阶段
        sparrow = search(sparrow, best_population)
        # 更新个体
        population[i] = sparrow
        # 更新最优个体
        if sparrow.fitness > best_sparrow.fitness:
            best_sparrow = deepcopy(sparrow)
    record2.append(best_sparrow.fitness)
plot_convergence([record2])

# %%


# 绘制收敛图的函数
def plot_convergence(convergence_records):
    num_curves = len(convergence_records)  
    
    for i in range(num_curves):
        cur = convergence_records[i]
        convergence_records[i] = [1 / i for i in cur]
    
    colors = ['b', 'g', 'r']  # 定义三条记录的颜色

    plt.figure(figsize=(20, 10))

    # 定义每条曲线的中文标签
    labels = ['NOA', 'NOA_SA', 'SSA']

    for i, record in enumerate(convergence_records):
        iterations = list(range(1, len(record) + 1))
        plt.plot(iterations, record, marker='o', label=labels[i], color=colors[i])

    plt.title('Convergence Plots')  
    plt.xlabel('Itterations')
    plt.ylabel('Cost')
    plt.legend()
    plt.grid(False)  
    plt.show()


convergence_records = [record, record1, record2]
print(f'NOA:{record}')
print(f'NOA_SA:{record1}')
print(f'SSA:{record2}')

# 调用函数绘制图表
plot_convergence(convergence_records)
**需软件开发兼职接项目,请通过手机端搜小#程#序: "黄页小艺"** 。

这段代码实现了一个基于星雀(Nutcracker)和麻雀(Sparrow)算法的物流配送路径规划问题求解程序,主要功能包括以下几个方面:

一、问题定义与参数设置

  1. 定义了物流配送中的各种参数,如需求点数量、供应点数量、冷库数量、产品种类、车辆数等。
  2. 生成了需求矩阵、时间窗、车辆容量、车辆承重和体积、车辆速度和行驶距离、车辆成本、产品重量和体积、冷库建设成本等数据。
  3. 定义了节点坐标和距离矩阵。

二、算法实现

  1. 整数转二进制函数toBit函数将一个整数转换为特定长度的二进制表示,用于后续的编码和解码操作。

  2. 个体类定义

    • Nutcracker类表示星雀个体,包含个体的编码、解码和适应度计算方法。解码过程根据个体编码确定车辆的服务顺序和路径,计算各种成本(冷库建设成本、车辆运输成本、需求延误成本)作为适应度。
    • Sparrow类表示麻雀个体,功能与星雀个体类似,也包含编码、解码和适应度计算方法。
  3. 生成个体和种群

    • gen_nutcracker函数生成星雀个体,包括随机生成的车辆分配、车辆顺序和服务顺序。
    • gen_sparrow函数生成麻雀个体,方式与生成星雀个体类似。
    • get_population函数根据给定数量生成星雀或麻雀种群。
  4. 获取最优个体get_best_nutcrackerget_best_sparrow函数分别用于在星雀和麻雀种群中获取适应度最高的个体。

  5. 觅食阶段forage函数实现了星雀和麻雀的觅食行为,包括随机探索和最优探索两种方式。

  6. 储存阶段store函数将当前个体加入到最佳种群中,并返回更新后的最佳种群。

  7. 缓存搜索阶段

    • search函数根据 Levy 飞行距离在最佳种群中进行搜索,生成新的个体,如果新个体适应度更高则更新当前个体。
    • new_search函数在search函数的基础上增加了交换操作,进一步探索解空间。
  8. 混沌初始化种群chaos_initialize_sparrows函数使用 Logistic 映射生成混沌序列,用于初始化麻雀种群,增加种群的多样性。

  9. Levy 飞行距离计算levy_distance函数计算两个个体之间的 Levy 飞行距离,用于缓存搜索阶段判断个体之间的相似性。

三、算法运行与结果展示

  1. 基础算法运行

    • 设置种群数量、储存数量、迭代次数、探索概率和飞行距离等参数。
    • 生成初始种群,找到最优个体。
    • 通过迭代进行觅食、储存和缓存搜索等操作,更新种群和最优个体,并记录最优个体的适应度。
    • 绘制收敛图,展示算法在迭代过程中适应度的变化情况。
    • 绘制路线图,使用 Folium 库在地图上展示车辆的行驶路径。
  2. 改进算法运行:与基础算法类似,但在觅食阶段增加了基于适应度差值和随机概率的接受新个体的条件。

  3. 麻雀算法运行

    • 定义麻雀个体和相关操作,与星雀算法类似。
    • 生成麻雀种群,进行迭代求解,记录适应度并绘制收敛图。
  4. 综合结果展示

    • 定义绘制收敛图的函数plot_convergence,可以同时展示多个算法的收敛情况,并为每条曲线添加中文标签。
    • 将三种算法(基础算法、改进算法、麻雀算法)的收敛记录合并,调用plot_convergence函数绘制综合收敛图。

总体来说,这段代码通过实现不同的优化算法来解决物流配送中的路径规划问题,包括确定车辆的分配、服务顺序和路径,以最小化总成本。同时,通过绘制收敛图和路线图展示算法的性能和结果。
需软件开发兼职接项目,请通过手机端搜小#程#序: "黄页小艺"

相关推荐
肥猪猪爸1 小时前
使用卡尔曼滤波器估计pybullet中的机器人位置
数据结构·人工智能·python·算法·机器人·卡尔曼滤波·pybullet
readmancynn1 小时前
二分基本实现
数据结构·算法
萝卜兽编程1 小时前
优先级队列
c++·算法
盼海1 小时前
排序算法(四)--快速排序
数据结构·算法·排序算法
一直学习永不止步2 小时前
LeetCode题练习与总结:最长回文串--409
java·数据结构·算法·leetcode·字符串·贪心·哈希表
Rstln2 小时前
【DP】个人练习-Leetcode-2019. The Score of Students Solving Math Expression
算法·leetcode·职场和发展
芜湖_3 小时前
【山大909算法题】2014-T1
算法·c·单链表
珹洺3 小时前
C语言数据结构——详细讲解 双链表
c语言·开发语言·网络·数据结构·c++·算法·leetcode
几窗花鸢3 小时前
力扣面试经典 150(下)
数据结构·c++·算法·leetcode
.Cnn3 小时前
用邻接矩阵实现图的深度优先遍历
c语言·数据结构·算法·深度优先·图论