% 参数定义
n = 20; % 候选二级物流节点数量
m = 163; % 客户数量
d_center = [12048 3901]; % 配送中心坐标
node_capacity = 10000; % 节点容量限制 (吨)
vehicle_capacity = 10; % 车辆容量 (吨)
operating_cost = 400; % 节点开放成本(c0)
cr1 = 300; % 车辆租赁成本
c0_cost = 200; % 车辆启动成本
c1 = 0.64; % 载重运输成本系数
max_distance = 400; % 车辆最大单程行驶距离
c2 = 1.96;
% 导入数据
distance_matrix = xlsread('距离.xlsx');
data = xlsread('新建 Microsoft Excel 工作表.xlsx', 'Sheet1');
% 验证数据维度
if size(data, 2) < 6
error('Excel数据必须包含至少6列:位置1-2是客户坐标,位置3-4是其他数据,位置5-6是需求量');
end
% 创建正确的数据结构
customer_coords = data(:, 1:2); % 客户位置坐标
demand_data = [data(:, 5), data(:, 6)]; % 每个客户的配送量和回收量
total_demand = sum(demand_data, 2); % 客户总需求
% 创建三维数据结构:[坐标x, 坐标y, 总需求量]
delivery_data = [customer_coords, total_demand];
crossOverRate = 0.8; % 交叉概率
% 生成候选节点坐标
rng(1);
candidate_nodes = d_center + 20 * (rand(n, 2) - 0.5);
% 遗传算法参数
pop_size = 100;
max_gen = 500;
mutation_rate = 0.1;
elite_rate = 0.1;
elite_num = round(pop_size * elite_rate);
% 初始化种群
population = false(pop_size, n);
for i = 1:pop_size
num_nodes = randi(n);
population(i, randperm(n, num_nodes)) = true;
end
% 遗传算法主循环
best_cost = Inf;
best_solution = false(1, n);
history = zeros(max_gen, 1); % 记录每代最优值
for gen = 1:max_gen
% 计算适应度
fitness = arrayfun(@(i) calculate_fitness(population(i,:), distance_matrix,...
delivery_data, vehicle_capacity, node_capacity, operating_cost,...
cr1, c0_cost, c1, c2, max_distance, d_center, candidate_nodes), 1:pop_size);
% 记录并排序适应度
[sorted_fitness, sorted_idx] = sort(fitness, 'descend');
history(gen) = -sorted_fitness(1); % 记录本代最佳成本
% 精英保留 - 直接复制最优个体到下一代
elite_pop = population(sorted_idx(1:elite_num), :);
% 锦标赛选择
tournament_size = 3; % 锦标赛规模
selected_parents = tournament_selection(population, fitness, pop_size - elite_num, tournament_size);
% 交叉操作
crossed_pop = crossover(selected_parents, crossOverRate);
% 变异操作
mutated_pop = mutation(crossed_pop, mutation_rate);
% 新种群 = 精英 + 交叉变异后的后代
population = [elite_pop; mutated_pop];
% 更新全局最优解
if -sorted_fitness(1) < best_cost
best_solution = population(sorted_idx(1),:);
best_cost = -sorted_fitness(1);
fprintf('Generation %d, New Best Cost: %.2f\n', gen, best_cost);
end
% 调试输出
if mod(gen,50)==0
fprintf('Generation %d, Best Cost: %.2f\n', gen, best_cost);
end
end
% 输出结果
% 输出结果
selected_nodes = find(best_solution);
node_coords = candidate_nodes(selected_nodes, :);
% 重新计算最优解的成本和客户分配
[~, ~, ~, ~, node_customers] = calculate_cost(best_solution, distance_matrix,...
delivery_data, vehicle_capacity, node_capacity, operating_cost,...
cr1, c0_cost, c1, c2, max_distance, d_center, candidate_nodes); % 添加d_center和candidate_nodes
disp(['最优节点数量: ', num2str(length(selected_nodes))]);
disp(['节点索引: ', num2str(selected_nodes(:)')]);
disp(['最低成本: ', num2str(best_cost)]);
disp('====== 选定节点坐标 ======');
for i = 1:length(selected_indices)
coord = candidate_nodes(selected_indices(i),:);
disp(['节点 ', num2str(selected_indices(i)), ' : (', ...
num2str(coord(1)), ', ', num2str(coord(2)), ')']);
end
% 输出每个节点服务的客户
disp('====== 节点服务分配情况 ======');
for i = 1:length(selected_nodes)
node_id = selected_nodes(i);
num_customers = length(node_customers{i});
% 格式化客户列表输出(每行最多20个客户)
if num_customers == 0
disp(['节点 ' num2str(node_id) ' --> 未服务任何客户']);
else
customer_str = ['节点 ' num2str(node_id) ' --> 客户: '];
for j = 1:num_customers
customer_str = [customer_str, num2str(node_customers{i}(j))];
if mod(j,20)==0 || j==num_customers
disp(customer_str);
customer_str = ' '; % 缩进换行
else
customer_str = [customer_str, ', '];
end
end
end
end
function selected_pop = tournament_selection(population, fitness, num_select, tournament_size)
% 输入:
% population - 种群矩阵 (pop_size x chromosome_length)
% fitness - 适应度向量 (1 x pop_size)
% num_select - 需要选择的个体数量
% tournament_size - 锦标赛规模
%
% 输出:
% selected_pop - 选择出的种群子集
pop_size = size(population, 1);
selected_pop = false(num_select, size(population, 2));
for i = 1:num_select
% 随机选择参赛个体
contestants_idx = randperm(pop_size, tournament_size);
% 找出锦标赛中适应度最高的个体
[~, best_idx] = max(fitness(contestants_idx));
% 存储获胜者
selected_pop(i, :) = population(contestants_idx(best_idx), :);
end
end
function mutated_pop = mutation(population, rate)
mutated_pop = population;
for i = 1:size(population, 1)
% 生成变异掩码
mutation_mask = rand(1, size(population, 2)) < rate;
% 应用变异
mutated_pop(i, :) = xor(population(i, :), mutation_mask);
% 确保至少有一个节点被选中
if ~any(mutated_pop(i, :))
% 随机激活一个节点
idx = randi(size(population, 2));
mutated_pop(i, idx) = true;
end
end
end
% 修改后的交叉函数
function crossed_pop = crossover(parents, crossOverRate)
crossed_pop = false(size(parents));
num_parents = size(parents, 1);
for i = 1:2:num_parents-1
parent1 = parents(i, :);
parent2 = parents(i+1, :);
if rand < crossOverRate
% 单点交叉
cross_point = randi(length(parent1)-1);
child1 = [parent1(1:cross_point), parent2(cross_point+1:end)];
child2 = [parent2(1:cross_point), parent1(cross_point+1:end)];
crossed_pop(i, :) = child1;
crossed_pop(i+1, :) = child2;
else
% 保留原个体
crossed_pop(i, :) = parent1;
crossed_pop(i+1, :) = parent2;
end
end
% 处理奇数个父母的情况
if mod(num_parents, 2) == 1
crossed_pop(end, :) = parents(end, :);
end
end
% 独立适应度计算函
function fit = calculate_fitness(solution, distance_matrix, delivery_data,...
vehicle_capacity, node_capacity, operating_cost, cr1, c0_cost, c1, c2, ...
max_distance, d_center, candidate_nodes) % 增加两个参数
selected_nodes = find(solution);
[total_cost, ~, ~, ~, ~] = calculate_cost(solution, distance_matrix,...
delivery_data, vehicle_capacity, node_capacity, operating_cost,...
cr1, c0_cost, c1, c2, max_distance, d_center, candidate_nodes); % 添加两个参数
fit = -total_cost;
end
function fc1 = calculate_FC1(selected_nodes, node_opening_cost)
% selected_nodes: 逻辑向量表示被选中的节点
% node_opening_cost: 各节点的开放成本向量
fc1 = sum(node_opening_cost(selected_nodes));
end
function fc2 = calculate_FC2(selected_nodes, delivery_data, vehicle_capacity,...
lease_cost, startup_cost)
% lease_cost: 车辆租赁成本系数
% startup_cost: 车辆启动成本系数
num_nodes = sum(selected_nodes);
vehicle_counts = zeros(num_nodes,1);
task_counts = zeros(num_nodes,1);
% 计算每个节点的车辆需求和任务数量
for i = 1:num_nodes
node_demand = sum(delivery_data(selected_nodes(i),:));
vehicle_counts(i) = ceil(node_demand / vehicle_capacity);
task_counts(i) = sum(selected_nodes(i,:)) * 2; % 往返计为2个任务
end
fc2 = sum(lease_cost * vehicle_counts + startup_cost * task_counts);
end
function fc3 = calculate_FC3(route_matrix, load_matrix, distance_matrix,...
c1, c2)
% route_matrix: 路径选择矩阵(0/1)
% load_matrix: 载货量矩阵
[num_nodes, num_clients] = size(route_matrix);
fc3 = 0;
for i = 1:num_nodes
for j = 1:num_clients
if route_matrix(i,j)
% 载货运输成本 + 空驶返回成本
fc3 = fc3 + c1 * load_matrix(i,j) * distance_matrix(i,j) + ...
c2 * distance_matrix(i,j);
end
end
end
end
function [total_cost, breakdown] = total_cost_function(solution, params)
% params结构体包含所有成本参数和输入数据
selected_nodes = find(solution);
% 各成本分量计算
fc1 = calculate_FC1(selected_nodes, params.node_opening_cost);
fc2 = calculate_FC2(selected_nodes, params.delivery_data,...
params.vehicle_capacity, params.lease_cost, params.startup_cost);
fc3 = calculate_FC3(params.route_matrix, params.load_matrix,...
params.distance_matrix, params.c1, params.c2);
% 容量约束惩罚项
penalty = params.penalty_factor * any(params.node_demand > params.node_capacity);
total_cost = fc1 + fc2 + fc3 + penalty;
breakdown = [fc1, fc2, fc3, penalty];
end
% 修改后的成本计算函数
function [total_cost, fc1, fc2, fc3, node_customers] = calculate_cost(...
solution, dist_matrix, delivery_data, vehicle_cap, node_cap, ...
operating_cost, cr1, c0_cost, c1, c2, max_dist, d_center, candidate_nodes)
% 获取选中的节点索引
selected_indices = find(solution);
% 如果没有选中任何节点,返回高成本
if isempty(selected_indices)
total_cost = Inf;
fc1 = 0; fc2 = 0; fc3 = 0;
node_customers = {};
return;
end
% 获取选中节点的坐标
node_coords = candidate_nodes(selected_indices, :);
num_nodes = numel(selected_indices);
% 客户数量 (使用第一个非零维度)
m = size(delivery_data, 1);
% 初始化变量
node_demand = zeros(num_nodes, 1);
node_customers = cell(num_nodes, 1);
distance_violation = 0;
% FC1: 节点开放成本
fc1 = num_nodes * operating_cost;
% 计算配送中心到各节点的距离
dcenter_to_nodes = sqrt(sum((node_coords - d_center).^2, 2));
% 初始化其他成本项
fc2 = 0;
fc3 = 0;
% 分配客户到最近节点
for j = 1:m
% 计算当前客户坐标(如果delivery_data包含坐标,否则需要调整)
customer_coord = delivery_data(j, 1:2); % 假设前两列是坐标
% 计算所有节点到当前客户的距离
dist_to_customer = sqrt(sum((node_coords - customer_coord).^2, 2));
% 计算完整路径距离(配送中心->节点->客户)
full_distances = dcenter_to_nodes + dist_to_customer;
% 找出满足距离约束的节点
valid_nodes = full_distances <= max_dist;
if any(valid_nodes)
% 从满足约束的节点中选择最近的
[min_dist, idx] = min(full_distances(valid_nodes));
valid_indices = find(valid_nodes);
closest_idx = valid_indices(idx);
else
% 如果没有满足约束的节点,选择最近的一个并记录违反量
[min_dist, closest_idx] = min(full_distances);
distance_violation = distance_violation + (min_dist - max_dist);
end
% 累计节点需求
node_demand(closest_idx) = node_demand(closest_idx) + delivery_data(j, 3); % 假设第三列是需求量
% 记录客户分配
node_customers{closest_idx} = [node_customers{closest_idx}, j];
% 计算运输成本(往返)
fc3 = fc3 + 2 * (c1 * delivery_data(j, 3) * min_dist + c2 * min_dist);
end
% FC2: 车辆使用成本(基于节点需求)
vehicle_counts = ceil(node_demand / vehicle_cap);
fc2 = sum(vehicle_counts) * (cr1 + c0_cost);
% 容量约束惩罚
capacity_penalty = 1e6 * max(0, sum(node_demand) - node_cap);
% 距离约束惩罚
distance_penalty = 1e4 * max(0, distance_violation);
% 总成本
total_cost = fc1 + fc2 + fc3 + capacity_penalty + distance_penalty;
end====== 选定节点坐标 ======
函数或变量 'selected_indices' 无法识别。
出错 logistics_cost_model (第 104 行)
for i = 1:length(selected_indices)
最新发布