TSP旅行商问题,callback法(python实现)

本文介绍了如何使用Gurobi库在TSP问题中通过callback方法实现子环路消除,以c101数据集为例,通过求解得到旅行商最优路径和最小成本。
摘要由CSDN通过智能技术生成

 TSP中消除子环路的方法callback实现,使用solumn数据集里面的'c101'数据集进行验证,选取前十个点进行验证

TSP问题一般形式

约束3是子环路消除约束

import numpy as np
from gurobipy import *
import math
import copy
import itertools
import networkx as nx


#TSP旅行商问题,callback法
def readData(path, nodeNum):
    cor_X = []
    cor_Y = []
    with open(path, 'r') as f:
        count = 0
        for line in f.readlines():
            count += 1
            if count >= 10 and count <= 10 + nodeNum:
                s = line.strip(' ').split()
                cor_X.append(float(s[1]))
                cor_Y.append(float(s[2]))
    
    distance = np.zeros((nodeNum, nodeNum))
    for i in range(nodeNum):
        for j in range(i + 1, nodeNum):
            dis = int(math.sqrt((cor_X[i] - cor_X[j]) ** 2 + (cor_Y[i] - cor_Y[j]) ** 2))
            distance[i][j] = distance[j][i] = dis
    return distance

def getValue(X, nodeNum):
    x_value = np.zeros((nodeNum+1, nodeNum+1)) 
    for key in X.keys():
        x_value[key[0], key[1]] = X[key].x
    return x_value

def getRoute(x_value):
    x = copy.deepcopy(x_value)
    current = 0
    path = [current]
    for i in range(len(x)):
        for j in range(len(x[i])):
            if(x[i][j] > 0):
                current = j
                path.append(current)
    path[-1]=0
    return path

def findEdges(graph):
    edges = []
    i, j = np.nonzero(graph > 0.5) # 返回大于阈值的元素的行列
    for k in range(len(i)):
        edges.append((i[k], j[k])) # 添加边
    return edges 

def subtour(graph):
    edges = findEdges(graph)
    G = nx.DiGraph(edges) # 创建有向图
    cycles = list(nx.simple_cycles(G)) # 找到所有简单回路
    min_cycle = min(cycles, key=len) # 找到最小的回路
    return min_cycle

def subtourelim(model, where): 
    if(where == GRB.Callback.MIPSOL):
        x_value = np.zeros((nodeNum + 1, nodeNum + 1))
        x_value1 = model.cbGetSolution(model._vars)
        for key,value in x_value1.items():
            x_value[key[0]][key[1]] = value
        tour = subtour(x_value)
        if(len(tour) < nodeNum + 1):  
            model.cbLazy(quicksum(model._vars[i, j]
                                      for i,j in itertools.permutations(tour, 2))
                             <= len(tour)-1)  # 添加约束,消除子回路
          
path = r'C:\Users\11366\Desktop\solomn_data\c101.txt'
nodeNum = 10 # 节点数量
distance = readData(path, nodeNum) # 读取距离矩阵
model = Model() 
# 创建变量
X = {} 
for i in range (nodeNum+1):
    for j in range(nodeNum+1):
        if i!= j:
            X[i, j]=model.addVar(vtype = GRB.BINARY, name = 'x_' + str(i) + '_' + str(j))

obj = LinExpr(0)
for key in X.keys():
    i,j = key[0],key[1]
    if(i < nodeNum and j < nodeNum):
        obj.addTerms(distance[i][j], X[key])
    elif(i == nodeNum):
        obj.addTerms(distance[0][j], X[key])
    elif(j == nodeNum):
        obj.addTerms(distance[i][0], X[key])
model.setObjective(obj, GRB.MINIMIZE)

for j in range(1,nodeNum+1):
    exp = LinExpr(0)
    for i in range(nodeNum):
        if i!= j:
            exp.addTerms(1,X[i, j])
    model.addConstr(exp == 1)

for i in range(nodeNum):
    exp = LinExpr(0)
    for j in range(1,nodeNum+1):
        if i!= j:
            exp.addTerms(1,X[i, j])
    model.addConstr(exp == 1)

#需要添加x_{ij} + x_{ji} <=1
for i in range(0, nodeNum):
    for j in range(i+1, nodeNum):
        exp = LinExpr(0)
        exp.addTerms(1, X[i, j])
        exp.addTerms(1, X[j, i])
        model.addConstr(exp <= 1)

model._vars = X 
model.Params.lazyConstraints = 1
model.optimize(subtourelim)
x_value = getValue(X, nodeNum) 
route = getRoute(x_value)
print('Optimal route:', route)
print('Optimal cost:', model.objVal)

运行结果:

Optimal route: [0, 7, 3, 1, 5, 2, 10, 4, 8, 9, 0]
Optimal cost: 48.0

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值