77、CVRP方法(整数规划、横扫式聚类、层次聚类、扫描法、T2C)

整数规划建模

import random as rd
from pyscipopt import Model, quicksum
from tool.Distance import calculate_distance
from VRP.CVRP.tool.Plot import *
from VRP.CVRP.tool.Print import *
from VRP.CVRP.tool.Data_generate import *

#一维装箱整数规划
def IP_1d(points, capacity, time_limit):

    n = len(points)

    model = Model("IP_1d")

    #i为车子下标,j为点下标
    X = [[model.addVar(vtype="B", name="x[%s,%s]" % (i, j)) for j in range(n)] for i in range(n)]
    Y = [model.addVar(vtype="B", name="y[%s]" % i) for i in range(n)]

    #以总包裹体积最小(即填充率最大)为目标
    model.setObjective(quicksum(Y[i] for i in range(n)), "minimize")

    #每个车子内货量不超
    for i in range(n):
        model.addCons(quicksum(points[j].demand*X[i][j] for j in range(n)) - capacity*Y[i] <= 0)

    #每个商品都能被装下
    for j in range(n):
        model.addCons(quicksum(X[i][j] for i in range(n)) == 1)

    #设置求解时间
    model.setRealParam("limits/time", time_limit)
    # model.hideOutput()
    model.optimize()
    print("\ngap:",model.getGap())

    X1 = [[round(model.getVal(X[i][j])) for j in range(n)] for i in range(n)]
    Y1 = [round(model.getVal(Y[i])) for i in range(n)]

    return sum(Y1)

#附:列出L的所有真子集
def subset(L):
    LL = []
    n = len(L)
    for i in range(1, pow(2, n)-1):
        L1 = []
        temp = i
        for j in range(n):
            if temp%2 == 1:
                L1.append(L[j])
            temp = temp//2
        LL.append(L1)
    return LL

def CVRP_IP(points, K, capacity, time_limit):
    n = len(points)
    Dis = [[calculate_distance(points[i].x, points[i].y, points[j].x, points[j].y, "EUC") for j in range(n)] for i in
           range(n)]

    model = Model("CVRP_IP")

    X = [[model.addVar(vtype="B", name="X[%s,%s]" % (i, j)) for j in range(n)] for i in range(n)]
    Y = [[model.addVar(vtype="B", name="Y[%s,%s]" % (i, k)) for k in range(K)] for i in range(n)]
    f = [[[model.addVar(vtype="B", name="f[%s,%s,%s]" % (i, j, k)) for k in range(K)] for j in range(n)] for i in range(n)]

    model.setObjective(quicksum(Dis[i][j] * X[i][j] for i in range(n) for j in range(n)), "minimize")

    #几辆车的约束
    model.addCons(quicksum(X[0][j] for j in range(1, n)) == K)
    model.addCons(quicksum(X[j][0] for j in range(1, n)) == K)

    #其余一度约束
    for i in range(1, n):
        model.addCons(quicksum(X[i][j] for j in range(n) if i != j) == 1)
        model.addCons(quicksum(X[j][i] for j in range(n) if i != j) == 1)

    #无子环约束
    SS = subset([i for i in range(n)])
    for S in SS:
        model.addCons(quicksum(X[i][j] for i in S for j in range(n) if j not in S) >= 1)

    #车辆容积限制
    for k in range(K):
        model.addCons(quicksum(points[i].demand*Y[i][k] for i in range(n)) <= capacity)

    #点必须被分配出去
    for i in range(1, n):
        model.addCons(quicksum(Y[i][k] for k in range(K)) == 1)

    #起点在每辆车上
    for k in range(K):
        model.addCons(Y[0][k] == 1)

    #点放在一起的约束
    for i in range(n):
        for j in range(n):
            model.addCons(X[i][j] <= quicksum(f[i][j][k] for k in range(K)))
            for k in range(K):
                model.addCons(Y[i][k] + Y[j][k] >= 2*f[i][j][k])

    # 设置求解时间
    model.setRealParam("limits/time", time_limit)
    model.optimize()
    print("\ngap:", model.getGap())

    X1 = [[round(model.getVal(X[i][j])) for j in range(n)] for i in range(n)]

    return X1

def IP(points, capacity, time_limit):
    #确定车数
    K = IP_1d(points, capacity, time_limit)
    print("\nK:", K)

    #分配点数
    A = CVRP_IP(points, K, capacity, time_limit)
    LL_print("\nA: ", A)
    return A

def price(A, Dis):
    n = len(A)
    return sum([Dis[i][j] * A[i][j] for i in range(n) for j in range(n)])

if __name__ == "__main__":

    #这里先定义一下标准的CVRP问题,简单的,先看同构车型
    #点的范围及个数
    x_min, y_min, x_max, y_max, nums = 0,0,100,100,10

    #车容量
    capacity = 3

    #点集生成
    points = points_generate_CVRP(x_min, y_min, x_max, y_max, nums, capacity)
    print("\npoints", points)

    A = IP(points, capacity, 100)

    #价值及画图
    Dis = [[calculate_distance(points[i].x, points[i].y, points[j].x, points[j].y, "EUC") for j in range(nums)] for i in
           range(nums)]
    print("A:", price(A, Dis))
    A1 = [[1 if i < j and (A[i][j] == 1 or A[j][i] == 1) else 0 for j in range(len(points))] for i in range(len(points))]
    A_plot(points, A1, x_min, y_min, x_max, y_max)

横扫式聚类

from tool.Distance import calculate_distance
from VRP.CVRP.tool.Plot import *
from VRP.CVRP.tool.Print import *
from TSP.Heuristic import TSP_insert
from VRP.CVRP.tool.Data_generate import *
from VRP.CVRP.tool.Graph_transform import *

def clustering(points, capacity):

    p0 = points[0]
    points1 = points[1:]
    points1.sort(key=lambda p: p.x)

    #横扫式聚类
    LLP = []
    points1_used = [0 for i in range(len(points1))]
    while sum(points1_used) < len(points1_used):
        LP = []
        start = 0
        for i in range(len(points1_used)):
            if points1_used[i] == 0:
                start = i
                LP.append(points1[start])
                points1_used[start] = 1
                break
        dis = [[i, calculate_distance(points1[start].x, points1[start].y, points1[i].x, points1[i].y, "EUC")] for i in range(len(points1)) if points1_used[i] == 0]
        dis.sort(key=lambda x:x[1])

        if len(dis) > 0:
            count = points1[start].demand
            i = 0
            while i < len(dis):
                if count+points1[dis[i][0]].demand > capacity:
                    break
                else:
                    LP.append(points1[dis[i][0]])
                    count += points1[dis[i][0]].demand
                    points1_used[dis[i][0]] = 1
                    i += 1
        LLP.append(LP)

    #每片作TSP
    edges = set()
    for LP in LLP:
        pointsi = [[0, p0.x, p0.y]] + [[j+1, LP[j].x, LP[j].y] for j in range(len(LP))]
        D = {0:0}
        for j in range(len(LP)):
            D[j+1] = LP[j].ID
        Dis = [[calculate_distance(pointsi[i][1], pointsi[i][2], pointsi[j][1], pointsi[j][2], "EUC") for j in
                range(len(pointsi))] for i in range(len(pointsi))]
        A_insert = TSP_insert(pointsi, Dis)
        for i in range(len(A_insert)):
            for j in range(i+1, len(A_insert)):
                if A_insert[i][j] == 1:
                    edges.add((D[i],D[j]))

    X = [[1 if (points[i].ID, points[j].ID) in edges or (points[j].ID, points[i].ID) in edges else 0 for j in range(len(points))] for i in range(len(points))]

    return Unirected_to_directed(X)

def price(A, Dis):
    n = len(A)
    return sum([Dis[i][j] * A[i][j] for i in range(n) for j in range(n)])

if __name__ == "__main__":

    #这里先定义一下标准的CVRP问题,简单的,先看同构车型
    #点的范围及个数
    x_min, y_min, x_max, y_max, nums = 0,0,100,100,10

    #车容量
    capacity = 4

    #点集生成
    points = points_generate_CVRP(x_min, y_min, x_max, y_max, nums, capacity)
    print(points)

    A = clustering(points, capacity)
    LL_print("A", A)

    #价值及画图
    Dis = [[calculate_distance(points[i].x, points[i].y, points[j].x, points[j].y, "EUC") for j in range(nums)] for i in range(nums)]
    print("A:", price(A, Dis))
    A_plot(points, A, x_min, y_min, x_max, y_max)

层次聚类

from tool.Distance import calculate_distance
from VRP.CVRP.tool.Plot import *
from VRP.CVRP.tool.Print import *
from TSP.Heuristic import TSP_insert
from VRP.CVRP.tool.Data_generate import *
from VRP.CVRP.tool.Graph_transform import *

def hierarchical_clustering(points, capacity):

    p0 = points[0]
    points1 = points[1:]

    #以带约束的层次聚类方法初始化
    LLP = [[points1[i]] for i in range(len(points1))]
    flag = True
    while flag:
        flag = False
        Dis = [[i,j,calculate_distance(sum([point.x for point in LLP[i]])/len(LLP[i]), sum([point.y for point in LLP[i]])/len(LLP[i]),
                                       sum([point.x for point in LLP[j]])/len(LLP[j]), sum([point.y for point in LLP[j]])/len(LLP[j]), "EUC")]
               for i in range(len(LLP)) for j in range(i+1, len(LLP))]
        Dis.sort(key=lambda x:x[2])
        for pair in Dis:
            i, j = pair[0], pair[1]
            #合并条件:载重,载容,件数,团点
            if sum([point.demand for point in LLP[i]]) + sum([point.demand for point in LLP[j]]) <= capacity:
                LLP = LLP[:i] + LLP[i+1:j] + LLP[j+1:] + [LLP[i]+LLP[j]]
                flag = True
                break

    edges = set()
    for LP in LLP:
        pointsi = [[0, p0.x, p0.y]] + [[j+1, LP[j].x, LP[j].y] for j in range(len(LP))]
        D = {0:0}
        for j in range(len(LP)):
            D[j+1] = LP[j].ID
        Dis = [[calculate_distance(pointsi[i][1], pointsi[i][2], pointsi[j][1], pointsi[j][2], "EUC") for j in
                range(len(pointsi))] for i in range(len(pointsi))]
        A_insert = TSP_insert(pointsi, Dis)
        for i in range(len(A_insert)):
            for j in range(i+1, len(A_insert)):
                if A_insert[i][j] == 1:
                    edges.add((D[i],D[j]))

    X = [[1 if (points[i].ID, points[j].ID) in edges or (points[j].ID, points[i].ID) in edges else 0 for j in range(len(points))] for i in range(len(points))]

    return Unirected_to_directed(X)

def price(A, Dis):
    n = len(A)
    return sum([Dis[i][j] * A[i][j] for i in range(n) for j in range(n)])

if __name__ == "__main__":

    #这里先定义一下标准的CVRP问题,简单的,先看同构车型
    #点的范围及个数
    x_min, y_min, x_max, y_max, nums = 0,0,100,100,10

    #车容量
    capacity = 4

    #点集生成
    points = points_generate_CVRP(x_min, y_min, x_max, y_max, nums, capacity)
    print(points)

    A = hierarchical_clustering(points, capacity)
    LL_print("A", A)

    #价值及画图
    Dis = [[calculate_distance(points[i].x, points[i].y, points[j].x, points[j].y, "EUC") for j in range(nums)] for i in range(nums)]
    print("A:", price(A, Dis))
    A_plot(points, A, x_min, y_min, x_max, y_max)

扫描法

from tool.Distance import calculate_distance
from VRP.CVRP.tool.Plot import *
from VRP.CVRP.tool.Print import *
from TSP.Heuristic import TSP_insert
from VRP.CVRP.tool.Data_generate import *
from VRP.CVRP.tool.Graph_transform import *

import math

def angle_dir(p0, p1):
    dx, dy = p1.x-p0.x, p1.y-p0.y
    if dx > 0:
        if dy >= 0:
            angle = math.atan(dy/dx)
        else:
            angle = math.atan(dy/dx) + 2*math.pi
    elif dx == 0:
        if dy > 0:
            angle = math.pi/2
        elif dy == 0:
            angle = 0
        else:
            angle = math.pi*3/2
    else:
        angle = math.atan(dy/dx)+math.pi
    return angle

def sweep(points, capacity):

    p0 = points[0]
    points1 = points[1:]

    #按极坐标排序
    LL = [[points1[i], angle_dir(p0, points1[i])] for i in range(len(points1))]
    LL.sort(key=lambda x:x[1])
    points1 = [L[0] for L in LL]

    #初始化片区
    LLP = [[]]
    c = 0
    for p in points1:
        if p.demand + c <= capacity:
            LLP[-1].append(p)
            c += p.demand
        else:
            LLP.append([p])
            c = p.demand

    edges = set()
    for LP in LLP:
        pointsi = [[0, p0.x, p0.y]] + [[j+1, LP[j].x, LP[j].y] for j in range(len(LP))]
        D = {0:0}
        for j in range(len(LP)):
            D[j+1] = LP[j].ID
        Dis = [[calculate_distance(pointsi[i][1], pointsi[i][2], pointsi[j][1], pointsi[j][2], "EUC") for j in
                range(len(pointsi))] for i in range(len(pointsi))]
        A_insert = TSP_insert(pointsi, Dis)
        for i in range(len(A_insert)):
            for j in range(i+1, len(A_insert)):
                if A_insert[i][j] == 1:
                    edges.add((D[i],D[j]))

    X = [[1 if (points[i].ID, points[j].ID) in edges or (points[j].ID, points[i].ID) in edges else 0 for j in range(len(points))] for i in range(len(points))]

    return Unirected_to_directed(X)

def price(A, Dis):
    n = len(A)
    return sum([Dis[i][j] * A[i][j] for i in range(n) for j in range(n)])

if __name__ == "__main__":

    #这里先定义一下标准的CVRP问题,简单的,先看同构车型
    #点的范围及个数
    x_min, y_min, x_max, y_max, nums = 0,0,100,100,30

    #车容量
    capacity = 10

    #点集生成
    points = points_generate_CVRP(x_min, y_min, x_max, y_max, nums, capacity)
    print(points)

    A = sweep(points, capacity)
    LL_print("A", A)

    #价值及画图
    Dis = [[calculate_distance(points[i].x, points[i].y, points[j].x, points[j].y, "EUC") for j in range(nums)] for i in range(nums)]
    print("A:", price(A, Dis))
    A_plot(points, A, x_min, y_min, x_max, y_max)

T2C

from tool.Distance import calculate_distance
from VRP.CVRP.tool.Plot import *
from VRP.CVRP.tool.Print import *
from TSP.Heuristic import TSP_insert
from VRP.CVRP.tool.Data_generate import *
from VRP.CVRP.tool.Graph_transform import *

def X_init(points):
    D = {}
    for j in range(len(points)):
        D[j] = points[j]
    points1 = [[j, points[j].x, points[j].y] for j in range(len(points))]
    Dis = [[calculate_distance(points1[i][1], points1[i][2], points1[j][1], points1[j][2], "EUC") for j in range(len(points1))] for i in range(len(points1))]
    A_insert = TSP_insert(points1, Dis)

    edges = {i:[] for i in range(len(A_insert))}
    for i in range(len(A_insert)):
        for j in range(i+1, len(A_insert)):
            if A_insert[i][j] == 1:
                edges[i].append(j)
                edges[j].append(i)

    X = [0]
    now = 0
    while True:
        next = edges[now][0]
        if next in X:
            next = edges[now][1]
        if next in X:
            break
        X.append(next)
        now = next

    return [D[x] for x in X]

def T2C(points, capacity):

    p0 = points[0]

    #先把所有点串一下
    X = X_init(points)

    #初始化片区
    LLP = [[]]
    c = 0
    for p in X[1:]:
        if p.demand + c <= capacity:
            LLP[-1].append(p)
            c += p.demand
        else:
            LLP.append([p])
            c = p.demand

    #每片作TSP
    edges = set()
    for LP in LLP:
        pointsi = [[0, p0.x, p0.y]] + [[j+1, LP[j].x, LP[j].y] for j in range(len(LP))]
        D = {0:0}
        for j in range(len(LP)):
            D[j+1] = LP[j].ID
        Dis = [[calculate_distance(pointsi[i][1], pointsi[i][2], pointsi[j][1], pointsi[j][2], "EUC") for j in
                range(len(pointsi))] for i in range(len(pointsi))]
        A_insert = TSP_insert(pointsi, Dis)
        for i in range(len(A_insert)):
            for j in range(i+1, len(A_insert)):
                if A_insert[i][j] == 1:
                    edges.add((D[i],D[j]))

    X = [[1 if (points[i].ID, points[j].ID) in edges or (points[j].ID, points[i].ID) in edges else 0 for j in range(len(points))] for i in range(len(points))]

    return Unirected_to_directed(X)

def price(A, Dis):
    n = len(A)
    return sum([Dis[i][j] * A[i][j] for i in range(n) for j in range(n)])

if __name__ == "__main__":

    #这里先定义一下标准的CVRP问题,简单的,先看同构车型
    #点的范围及个数
    x_min, y_min, x_max, y_max, nums = 0,0,100,100,10

    #车容量
    capacity = 4

    #点集生成
    points = points_generate_CVRP(x_min, y_min, x_max, y_max, nums, capacity)
    print(points)

    A = T2C(points, capacity)
    LL_print("A", A)

    #价值及画图
    Dis = [[calculate_distance(points[i].x, points[i].y, points[j].x, points[j].y, "EUC") for j in range(nums)] for i in range(nums)]
    print("A:", price(A, Dis))
    A_plot(points, A, x_min, y_min, x_max, y_max)
  • 0
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值