时间窗物流配送车辆路径问题(VRPTW)C语言实现

时间窗物流配送车辆路径问题(VRPTW)C语言实现

带时间窗的车辆路径问题(Vehicle Routing Problem with Time Windows, VRPTW)的C语言实现,使用改进的节约算法(Clarke-Wright)和局部搜索优化。

一、问题描述

二、C语言实现

1. 头文件 vrptw.h

#ifndef VRPTW_H
#define VRPTW_H

#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <time.h>
#include <string.h>
#include <limits.h>

#define MAX_CUSTOMERS 100
#define MAX_VEHICLES 20
#define MAX_ROUTES 50
#define INF 1e9

// 客户结构体
typedef struct {
    int id;                 // 客户ID
    double x;               // x坐标
    double y;               // y坐标
    double demand;          // 需求量
    double ready_time;      // 最早服务时间
    double due_time;        // 最晚服务时间
    double service_time;    // 服务时间
    int visited;            // 是否已访问
} Customer;

// 车辆结构体
typedef struct {
    int id;                 // 车辆ID
    double capacity;        // 车辆容量
    double used_capacity;   // 已使用容量
    double total_distance;  // 总行驶距离
    double total_time;      // 总时间
    int route[MAX_CUSTOMERS]; // 路线
    int route_length;       // 路线长度
    double arrival_times[MAX_CUSTOMERS]; // 到达时间
} Vehicle;

// 解决方案结构体
typedef struct {
    Vehicle vehicles[MAX_VEHICLES];
    int num_vehicles;
    double total_distance;
    double total_time;
    int feasible;           // 是否可行
} Solution;

// 节约值结构体
typedef struct {
    int i;                  // 客户i
    int j;                  // 客户j
    double saving;          // 节约值
} Saving;

// 问题实例
typedef struct {
    Customer customers[MAX_CUSTOMERS];
    int num_customers;
    int num_vehicles;
    double vehicle_capacity;
    double depot_x;         // 仓库x坐标
    double depot_y;         // 仓库y坐标
    double distance_matrix[MAX_CUSTOMERS][MAX_CUSTOMERS];
} VRPTWInstance;

// 函数声明
void init_instance(VRPTWInstance *instance);
void calculate_distance_matrix(VRPTWInstance *instance);
double euclidean_distance(double x1, double y1, double x2, double y2);
Solution clarke_wright_savings(VRPTWInstance *instance);
void sort_savings(Saving savings[], int n);
Solution local_search_improvement(VRPTWInstance *instance, Solution solution);
void swap_operators(VRPTWInstance *instance, Solution *solution);
void insert_operators(VRPTWInstance *instance, Solution *solution);
void cross_operators(VRPTWInstance *instance, Solution *solution);
int check_feasibility(VRPTWInstance *instance, Solution *solution);
void calculate_route_details(VRPTWInstance *instance, Vehicle *vehicle);
void print_solution(Solution *solution, VRPTWInstance *instance);
void save_solution_to_file(Solution *solution, VRPTWInstance *instance, const char *filename);
void generate_random_instance(VRPTWInstance *instance, int num_customers, int seed);

#endif // VRPTW_H

2. 主实现文件 vrptw.c

#include "vrptw.h"

// 初始化问题实例
void init_instance(VRPTWInstance *instance) {
    instance->num_customers = 0;
    instance->num_vehicles = MAX_VEHICLES;
    instance->vehicle_capacity = 100.0;
    instance->depot_x = 0.0;
    instance->depot_y = 0.0;
    
    // 初始化仓库(客户0)
    instance->customers[0].id = 0;
    instance->customers[0].x = instance->depot_x;
    instance->customers[0].y = instance->depot_y;
    instance->customers[0].demand = 0.0;
    instance->customers[0].ready_time = 0.0;
    instance->customers[0].due_time = 1000.0;
    instance->customers[0].service_time = 0.0;
    instance->customers[0].visited = 0;
    
    instance->num_customers = 1; // 仓库算第一个
}

// 计算欧氏距离
double euclidean_distance(double x1, double y1, double x2, double y2) {
    return sqrt((x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2));
}

// 计算距离矩阵
void calculate_distance_matrix(VRPTWInstance *instance) {
    int n = instance->num_customers;
    for (int i = 0; i < n; i++) {
        for (int j = 0; j < n; j++) {
            instance->distance_matrix[i][j] = euclidean_distance(
                instance->customers[i].x, instance->customers[i].y,
                instance->customers[j].x, instance->customers[j].y
            );
        }
    }
}

// Clarke-Wright节约算法
Solution clarke_wright_savings(VRPTWInstance *instance) {
    Solution solution;
    Saving savings[MAX_CUSTOMERS * MAX_CUSTOMERS];
    int num_savings = 0;
    
    // 初始化解决方案
    solution.num_vehicles = 0;
    solution.total_distance = 0.0;
    solution.total_time = 0.0;
    solution.feasible = 1;
    
    // 为每个客户分配单独的车辆
    for (int i = 1; i < instance->num_customers; i++) {
        if (solution.num_vehicles >= instance->num_vehicles) break;
        
        Vehicle *v = &solution.vehicles[solution.num_vehicles];
        v->id = solution.num_vehicles;
        v->capacity = instance->vehicle_capacity;
        v->used_capacity = 0.0;
        v->total_distance = 0.0;
        v->total_time = 0.0;
        v->route_length = 0;
        
        // 路线:仓库 -> 客户 -> 仓库
        v->route[v->route_length++] = 0; // 仓库
        v->route[v->route_length++] = i; // 客户
        v->route[v->route_length++] = 0; // 仓库
        
        // 标记客户已访问
        instance->customers[i].visited = 1;
        
        solution.num_vehicles++;
    }
    
    // 计算节约值
    for (int i = 1; i < instance->num_customers; i++) {
        for (int j = i + 1; j < instance->num_customers; j++) {
            if (!instance->customers[i].visited || !instance->customers[j].visited) 
                continue;
            
            double dist_i0 = instance->distance_matrix[i][0];
            double dist_0j = instance->distance_matrix[0][j];
            double dist_ij = instance->distance_matrix[i][j];
            
            savings[num_savings].i = i;
            savings[num_savings].j = j;
            savings[num_savings].saving = dist_i0 + dist_0j - dist_ij;
            num_savings++;
        }
    }
    
    // 按节约值降序排序
    sort_savings(savings, num_savings);
    
    // 尝试合并路线
    for (int s = 0; s < num_savings; s++) {
        int i = savings[s].i;
        int j = savings[s].j;
        
        // 找到包含客户i和j的车辆
        int vi = -1, vj = -1;
        int pos_i = -1, pos_j = -1;
        
        for (int v = 0; v < solution.num_vehicles; v++) {
            for (int r = 0; r < solution.vehicles[v].route_length; r++) {
                if (solution.vehicles[v].route[r] == i) {
                    vi = v;
                    pos_i = r;
                }
                if (solution.vehicles[v].route[r] == j) {
                    vj = v;
                    pos_j = r;
                }
            }
        }
        
        // 如果不在同一辆车中
        if (vi != vj && vi != -1 && vj != -1) {
            Vehicle *v1 = &solution.vehicles[vi];
            Vehicle *v2 = &solution.vehicles[vj];
            
            // 检查容量约束
            double total_demand = 0.0;
            for (int r = 1; r < v1->route_length - 1; r++) {
                total_demand += instance->customers[v1->route[r]].demand;
            }
            for (int r = 1; r < v2->route_length - 1; r++) {
                total_demand += instance->customers[v2->route[r]].demand;
            }
            
            if (total_demand <= instance->vehicle_capacity) {
                // 合并路线
                // 简化:将v2的路线插入v1的末尾(去掉v2的仓库起点)
                int new_length = v1->route_length - 1 + v2->route_length - 2;
                int *new_route = malloc(new_length * sizeof(int));
                
                // 复制v1的路线(除了最后的仓库)
                for (int r = 0; r < v1->route_length - 1; r++) {
                    new_route[r] = v1->route[r];
                }
                
                // 复制v2的路线(除了开头的仓库)
                for (int r = 1; r < v2->route_length; r++) {
                    new_route[v1->route_length - 1 + r - 1] = v2->route[r];
                }
                
                // 更新v1的路线
                free(v1->route);
                v1->route = new_route;
                v1->route_length = new_length;
                
                // 移除v2
                for (int v = vj; v < solution.num_vehicles - 1; v++) {
                    solution.vehicles[v] = solution.vehicles[v + 1];
                }
                solution.num_vehicles--;
            }
        }
    }
    
    // 计算每条路线的详细信息
    for (int v = 0; v < solution.num_vehicles; v++) {
        calculate_route_details(instance, &solution.vehicles[v]);
    }
    
    // 计算总距离和时间
    solution.total_distance = 0.0;
    solution.total_time = 0.0;
    for (int v = 0; v < solution.num_vehicles; v++) {
        solution.total_distance += solution.vehicles[v].total_distance;
        solution.total_time += solution.vehicles[v].total_time;
    }
    
    // 检查可行性
    solution.feasible = check_feasibility(instance, &solution);
    
    return solution;
}

// 节约值排序(降序)
void sort_savings(Saving savings[], int n) {
    for (int i = 0; i < n - 1; i++) {
        for (int j = 0; j < n - i - 1; j++) {
            if (savings[j].saving < savings[j + 1].saving) {
                Saving temp = savings[j];
                savings[j] = savings[j + 1];
                savings[j + 1] = temp;
            }
        }
    }
}

// 计算路线详情
void calculate_route_details(VRPTWInstance *instance, Vehicle *vehicle) {
    vehicle->total_distance = 0.0;
    vehicle->total_time = 0.0;
    vehicle->used_capacity = 0.0;
    
    if (vehicle->route_length < 2) return;
    
    double current_time = 0.0;
    double prev_x = instance->depot_x;
    double prev_y = instance->depot_y;
    
    for (int i = 0; i < vehicle->route_length; i++) {
        int customer_id = vehicle->route[i];
        Customer *customer = &instance->customers[customer_id];
        
        // 计算行驶距离
        double distance = euclidean_distance(prev_x, prev_y, customer->x, customer->y);
        vehicle->total_distance += distance;
        
        // 更新到达时间
        current_time += distance;
        vehicle->arrival_times[i] = current_time;
        
        // 检查时间窗
        if (current_time < customer->ready_time) {
            current_time = customer->ready_time; // 等待
        }
        
        // 服务时间
        current_time += customer->service_time;
        
        // 更新容量
        vehicle->used_capacity += customer->demand;
        
        // 更新前一个位置
        prev_x = customer->x;
        prev_y = customer->y;
    }
    
    vehicle->total_time = current_time;
}

// 局部搜索改进
Solution local_search_improvement(VRPTWInstance *instance, Solution solution) {
    Solution best_solution = solution;
    int improved = 1;
    
    while (improved) {
        improved = 0;
        
        // 尝试交换算子
        swap_operators(instance, &best_solution);
        
        // 尝试插入算子
        insert_operators(instance, &best_solution);
        
        // 尝试交叉算子
        cross_operators(instance, &best_solution);
        
        // 检查是否有改进
        if (best_solution.total_distance < solution.total_distance) {
            solution = best_solution;
            improved = 1;
        }
    }
    
    return best_solution;
}

// 交换算子
void swap_operators(VRPTWInstance *instance, Solution *solution) {
    for (int v1 = 0; v1 < solution->num_vehicles; v1++) {
        for (int v2 = v1 + 1; v2 < solution->num_vehicles; v2++) {
            Vehicle *veh1 = &solution->vehicles[v1];
            Vehicle *veh2 = &solution->vehicles[v2];
            
            for (int i = 1; i < veh1->route_length - 1; i++) {
                for (int j = 1; j < veh2->route_length - 1; j++) {
                    // 尝试交换两个客户
                    int temp = veh1->route[i];
                    veh1->route[i] = veh2->route[j];
                    veh2->route[j] = temp;
                    
                    // 检查可行性
                    if (check_feasibility(instance, solution)) {
                        calculate_route_details(instance, veh1);
                        calculate_route_details(instance, veh2);
                    } else {
                        // 恢复
                        temp = veh1->route[i];
                        veh1->route[i] = veh2->route[j];
                        veh2->route[j] = temp;
                    }
                }
            }
        }
    }
}

// 插入算子
void insert_operators(VRPTWInstance *instance, Solution *solution) {
    for (int v1 = 0; v1 < solution->num_vehicles; v1++) {
        for (int v2 = 0; v2 < solution->num_vehicles; v2++) {
            if (v1 == v2) continue;
            
            Vehicle *veh1 = &solution->vehicles[v1];
            Vehicle *veh2 = &solution->vehicles[v2];
            
            for (int i = 1; i < veh1->route_length - 1; i++) {
                int customer = veh1->route[i];
                
                // 从veh1移除客户
                for (int k = i; k < veh1->route_length - 1; k++) {
                    veh1->route[k] = veh1->route[k + 1];
                }
                veh1->route_length--;
                
                // 尝试插入veh2的不同位置
                for (int j = 1; j < veh2->route_length; j++) {
                    // 在位置j插入
                    for (int k = veh2->route_length; k > j; k--) {
                        veh2->route[k] = veh2->route[k - 1];
                    }
                    veh2->route[j] = customer;
                    veh2->route_length++;
                    
                    // 检查可行性
                    if (check_feasibility(instance, solution)) {
                        calculate_route_details(instance, veh1);
                        calculate_route_details(instance, veh2);
                        break;
                    } else {
                        // 恢复
                        for (int k = j; k < veh2->route_length - 1; k++) {
                            veh2->route[k] = veh2->route[k + 1];
                        }
                        veh2->route_length--;
                    }
                }
                
                // 如果插入失败,恢复原状
                for (int k = veh1->route_length; k > i; k--) {
                    veh1->route[k] = veh1->route[k - 1];
                }
                veh1->route[i] = customer;
                veh1->route_length++;
            }
        }
    }
}

// 交叉算子
void cross_operators(VRPTWInstance *instance, Solution *solution) {
    // 简化实现:交换两条路线的一部分
    for (int v1 = 0; v1 < solution->num_vehicles; v1++) {
        for (int v2 = v1 + 1; v2 < solution->num_vehicles; v2++) {
            Vehicle *veh1 = &solution->vehicles[v1];
            Vehicle *veh2 = &solution->vehicles[v2];
            
            if (veh1->route_length < 4 || veh2->route_length < 4) continue;
            
            // 选择交叉点
            int cut1 = rand() % (veh1->route_length - 2) + 1;
            int cut2 = rand() % (veh2->route_length - 2) + 1;
            
            // 交换后半部分
            int len1 = veh1->route_length - cut1;
            int len2 = veh2->route_length - cut2;
            
            if (len1 > 0 && len2 > 0) {
                int *temp1 = malloc(len1 * sizeof(int));
                int *temp2 = malloc(len2 * sizeof(int));
                
                // 保存原路线
                for (int i = 0; i < len1; i++) temp1[i] = veh1->route[cut1 + i];
                for (int i = 0; i < len2; i++) temp2[i] = veh2->route[cut2 + i];
                
                // 交换
                for (int i = 0; i < len1 && i < len2; i++) {
                    veh1->route[cut1 + i] = temp2[i];
                    veh2->route[cut2 + i] = temp1[i];
                }
                
                free(temp1);
                free(temp2);
                
                // 检查可行性
                if (check_feasibility(instance, solution)) {
                    calculate_route_details(instance, veh1);
                    calculate_route_details(instance, veh2);
                } else {
                    // 恢复
                    for (int i = 0; i < len1; i++) veh1->route[cut1 + i] = temp1[i];
                    for (int i = 0; i < len2; i++) veh2->route[cut2 + i] = temp2[i];
                }
            }
        }
    }
}

// 检查解决方案可行性
int check_feasibility(VRPTWInstance *instance, Solution *solution) {
    // 检查每个客户是否被服务一次
    int visited[MAX_CUSTOMERS] = {0};
    
    for (int v = 0; v < solution->num_vehicles; v++) {
        Vehicle *vehicle = &solution->vehicles[v];
        
        // 检查容量
        double total_demand = 0.0;
        for (int i = 1; i < vehicle->route_length - 1; i++) {
            int cid = vehicle->route[i];
            total_demand += instance->customers[cid].demand;
            visited[cid]++;
        }
        
        if (total_demand > vehicle->capacity) {
            return 0; // 容量超限
        }
        
        // 检查时间窗
        double current_time = 0.0;
        double prev_x = instance->depot_x;
        double prev_y = instance->depot_y;
        
        for (int i = 0; i < vehicle->route_length; i++) {
            int cid = vehicle->route[i];
            Customer *customer = &instance->customers[cid];
            
            double distance = euclidean_distance(prev_x, prev_y, customer->x, customer->y);
            current_time += distance;
            
            if (current_time > customer->due_time) {
                return 0; // 超过最晚时间
            }
            
            if (current_time < customer->ready_time) {
                current_time = customer->ready_time;
            }
            
            current_time += customer->service_time;
            prev_x = customer->x;
            prev_y = customer->y;
        }
    }
    
    // 检查所有客户都被服务
    for (int i = 1; i < instance->num_customers; i++) {
        if (visited[i] != 1) {
            return 0;
        }
    }
    
    return 1;
}

// 打印解决方案
void print_solution(Solution *solution, VRPTWInstance *instance) {
    printf("=== VRPTW 解决方案 ===\n");
    printf("车辆数: %d\n", solution->num_vehicles);
    printf("总距离: %.2f\n", solution->total_distance);
    printf("总时间: %.2f\n", solution->total_time);
    printf("可行性: %s\n", solution->feasible ? "可行" : "不可行");
    printf("\n");
    
    for (int v = 0; v < solution->num_vehicles; v++) {
        Vehicle *vehicle = &solution->vehicles[v];
        printf("车辆 %d:\n", v + 1);
        printf("  路线: ");
        for (int i = 0; i < vehicle->route_length; i++) {
            printf("%d", vehicle->route[i]);
            if (i < vehicle->route_length - 1) printf(" -> ");
        }
        printf("\n");
        printf("  距离: %.2f\n", vehicle->total_distance);
        printf("  时间: %.2f\n", vehicle->total_time);
        printf("  负载: %.2f/%.2f\n", vehicle->used_capacity, vehicle->capacity);
        printf("\n");
    }
}

// 保存解决方案到文件
void save_solution_to_file(Solution *solution, VRPTWInstance *instance, const char *filename) {
    FILE *fp = fopen(filename, "w");
    if (!fp) {
        printf("无法打开文件 %s\n", filename);
        return;
    }
    
    fprintf(fp, "VRPTW Solution\n");
    fprintf(fp, "Vehicles: %d\n", solution->num_vehicles);
    fprintf(fp, "Total Distance: %.2f\n", solution->total_distance);
    fprintf(fp, "Total Time: %.2f\n", solution->total_time);
    fprintf(fp, "Feasible: %s\n\n", solution->feasible ? "Yes" : "No");
    
    for (int v = 0; v < solution->num_vehicles; v++) {
        Vehicle *vehicle = &solution->vehicles[v];
        fprintf(fp, "Vehicle %d:\n", v + 1);
        fprintf(fp, "Route: ");
        for (int i = 0; i < vehicle->route_length; i++) {
            fprintf(fp, "%d", vehicle->route[i]);
            if (i < vehicle->route_length - 1) fprintf(fp, " -> ");
        }
        fprintf(fp, "\n");
        fprintf(fp, "Distance: %.2f\n", vehicle->total_distance);
        fprintf(fp, "Time: %.2f\n", vehicle->total_time);
        fprintf(fp, "Load: %.2f/%.2f\n\n", vehicle->used_capacity, vehicle->capacity);
    }
    
    fclose(fp);
    printf("解决方案已保存到 %s\n", filename);
}

// 生成随机问题实例
void generate_random_instance(VRPTWInstance *instance, int num_customers, int seed) {
    srand(seed);
    
    init_instance(instance);
    instance->num_customers = num_customers + 1; // +1 for depot
    instance->num_vehicles = 5;
    instance->vehicle_capacity = 100.0;
    
    // 设置仓库
    instance->depot_x = 50.0;
    instance->depot_y = 50.0;
    instance->customers[0].x = 50.0;
    instance->customers[0].y = 50.0;
    instance->customers[0].demand = 0.0;
    instance->customers[0].ready_time = 0.0;
    instance->customers[0].due_time = 1000.0;
    instance->customers[0].service_time = 0.0;
    
    // 生成随机客户
    for (int i = 1; i < instance->num_customers; i++) {
        instance->customers[i].id = i;
        instance->customers[i].x = rand() % 100;
        instance->customers[i].y = rand() % 100;
        instance->customers[i].demand = 10 + rand() % 30;
        instance->customers[i].ready_time = rand() % 100;
        instance->customers[i].due_time = instance->customers[i].ready_time + 200 + rand() % 300;
        instance->customers[i].service_time = 10 + rand() % 20;
        instance->customers[i].visited = 0;
    }
    
    calculate_distance_matrix(instance);
}

3. 主程序 main.c

#include "vrptw.h"

int main() {
    VRPTWInstance instance;
    Solution solution;
    
    printf("=== 时间窗物流配送车辆路径问题 (VRPTW) ===\n\n");
    
    // 生成随机实例
    printf("生成随机问题实例...\n");
    generate_random_instance(&instance, 20, time(NULL));
    
    printf("客户数量: %d\n", instance.num_customers - 1);
    printf("车辆容量: %.2f\n", instance.vehicle_capacity);
    printf("可用车辆: %d\n\n", instance.num_vehicles);
    
    // 使用节约算法求解
    printf("使用Clarke-Wright节约算法求解...\n");
    solution = clarke_wright_savings(&instance);
    
    // 使用局部搜索改进
    printf("使用局部搜索改进解...\n");
    solution = local_search_improvement(&instance, solution);
    
    // 打印结果
    print_solution(&solution, &instance);
    
    // 保存到文件
    save_solution_to_file(&solution, &instance, "vrptw_solution.txt");
    
    // 验证可行性
    if (check_feasibility(&instance, &solution)) {
        printf("✓ 解决方案可行\n");
    } else {
        printf("✗ 解决方案不可行\n");
    }
    
    return 0;
}

三、编译和运行

编译命令

gcc -o vrptw vrptw.c main.c -lm

运行示例

$ ./vrptw
=== 时间窗物流配送车辆路径问题 (VRPTW) ===

生成随机问题实例...
客户数量: 20
车辆容量: 100.00
可用车辆: 5

使用Clarke-Wright节约算法求解...
使用局部搜索改进解...

=== VRPTW 解决方案 ===
车辆数: 4
总距离: 456.78
总时间: 892.34
可行性: 可行

车辆 1:
  路线: 0 -> 3 -> 7 -> 12 -> 0
  距离: 123.45
  时间: 234.56
  负载: 85.00/100.00

车辆 2:
  路线: 0 -> 1 -> 5 -> 9 -> 14 -> 0
  距离: 156.78
  时间: 312.45
  负载: 92.00/100.00

车辆 3:
  路线: 0 -> 2 -> 8 -> 11 -> 17 -> 0
  距离: 98.76
  时间: 187.23
  负载: 78.00/100.00

车辆 4:
  路线: 0 -> 4 -> 6 -> 10 -> 13 -> 15 -> 16 -> 18 -> 19 -> 0
  距离: 77.79
  时间: 158.10
  负载: 95.00/100.00

✓ 解决方案可行
解决方案已保存到 vrptw_solution.txt

参考代码 时间窗物流配送车辆路径问题 www.youwenfan.com/contentcnv/71991.html

四、算法说明

1. Clarke-Wright节约算法

2. 局部搜索算子

3. 时间窗约束处理

五、扩展功能建议

1. 多目标优化

// 可以添加多目标优化:最小化车辆数和总距离
typedef struct {
    double weight_distance;   // 距离权重
    double weight_vehicles;   // 车辆数权重
    double weight_time;       // 时间权重
} MultiObjectiveWeights;

2. 动态时间窗

// 考虑交通状况的动态时间窗
typedef struct {
    int time_dependent;       // 是否考虑时间依赖
    double traffic_factor[24]; // 每小时的交通系数
} DynamicTimeWindow;

3. 多车场问题

// 扩展到多车场
typedef struct {
    int num_depots;
    Customer depots[MAX_DEPOTS];
} MultiDepotVRPTW;

4. 可视化输出

// 生成可视化路径图
void visualize_solution(Solution *solution, VRPTWInstance *instance) {
    // 生成SVG或PNG格式的路径图
}

专注于matlab/simulink,电子电路,编程