You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何修改代码实现起点终点不同的旅行商问题(TSP)求解?

非闭合路径旅行商问题(TSP)求解修改指导

问题描述

这是旅行商问题(Travelling Salesman Problem,TSP),需要实现起点与终点不同的求解逻辑,现有常规闭合路径(起点终点相同)的Python求解代码和JavaScript全排列求解代码,以下是针对性修改方案。


现有闭合路径TSP代码

Python实现(闭合路径)

def Min(lst,myindex):
    return min(x for idx, x in enumerate(lst) if idx != myindex)

def Delete(matrix,index1,index2):
    del matrix[index1]
    for i in matrix:
        del i[index2]
    return matrix

def PrintMatrix(matrix):
    print("---------------")
    for i in range(len(matrix)):
        print(matrix[i])
    print("---------------")

n=int(input())
matrix=[]
H=0
PathLenght=0
Str=[]
Stb=[]
res=[]
result=[]
StartMatrix=[]

for i in range(n):
    Str.append(i)
    Stb.append(i)

for i in range(n): matrix.append(list(map(int, input().split())))
    
for i in range(n):StartMatrix.append(matrix[i].copy())

float(inf)
for i in range(n): matrix[i][i]=float('inf')

while True:
    for i in range(len(matrix)):
        temp=min(matrix[i])
        H+=temp
        for j in range(len(matrix)):
            matrix[i][j]-=temp
 
    for i in range(len(matrix)):
        temp = min(row[i] for row in matrix)
        H+=temp
        for j in range(len(matrix)):
            matrix[j][i]-=temp
    
    NullMax=0
    index1=0
    index2=0
    tmp=0
    for i in range(len(matrix)):
        for j in range(len(matrix)):
            if matrix[i][j]==0:
                tmp=Min(matrix[i],j)+Min((row[j] for row in matrix),i)
                if tmp>=NullMax:
                    NullMax=tmp
                    index1=i
                    index2=j

    res.append(Str[index1]+1)
    res.append(Stb[index2]+1)
    
    oldIndex1=Str[index1]
    oldIndex2=Stb[index2]
    if oldIndex2 in Str and oldIndex1 in Stb:
        NewIndex1=Str.index(oldIndex2)
        NewIndex2=Stb.index(oldIndex1)
        matrix[NewIndex1][NewIndex2]=float('inf')
    del Str[index1]
    del Stb[index2]
    matrix=Delete(matrix,index1,index2)
    if len(matrix)==1:break
    
for i in range(0,len(res)-1,2):
    if res.count(res[i])<2:
        result.append(res[i])
        result.append(res[i+1])
for i in range(0,len(res)-1,2):
    for j in range(0,len(res)-1,2):
        if result[len(result)-1]==res[j]:
            result.append(res[j])
            result.append(res[j+1])
print("----------------------------------")
print(result)

for i in range(0,len(result)-1,2):
    if i==len(result)-2:
        PathLenght+=StartMatrix[result[i]-1][result[i+1]-1]
        PathLenght+=StartMatrix[result[i+1]-1][result[0]-1]
    else: PathLenght+=StartMatrix[result[i]-1][result[i+1]-1]
print(PathLenght)
print("----------------------------------")
input()

代码运行示例

  • 输入:4
  • 输入4×4矩阵:
0 10 1 1
10 0 1 5
1 1 0 10
1 5 10 0
  • 输出结果:[1,4,4,2,2,3,3,1],总长度8(闭合路径:1->4->2->3->1)

JavaScript全排列实现(闭合路径)

let towns = [
  [0, 28, 58, 13, 24, 25, 31, 64],
  [28, 0, 82, 15, 52, 27, 33, 54],
  [58, 82, 0, 67, 82, 64, 49, 97],
  [13, 15, 67, 0, 37, 12, 18, 69],
  [24, 52, 82, 37, 0, 49, 53, 40],
  [25, 27, 64, 12, 49, 0, 15, 81],
  [31, 33, 49, 18, 53, 15, 0, 70],
  [64, 54, 97, 69, 40, 81, 70, 0],
];

let path = [];
let counter = 0;
let minPath = 10000;
let minCounter;

for (let i1 = 0; i1 <= 7; i1++) {
  for (let i2 = 0; i2 <= 7; i2++) {
    for (let i3 = 0; i3 <= 7; i3++) {
      for (let i4 = 0; i4 <= 7; i4++) {
        for (let i5 = 0; i5 <= 7; i5++) {
          for (let i6 = 0; i6 <= 7; i6++) {
            for (let i7 = 0; i7 <= 7; i7++) {
              for (let i8 = 0; i8 <= 7; i8++) {
                if (
                  i1 != i2 &&
                  i1 != i3 &&
                  i1 != i4 &&
                  i1 != i5 &&
                  i1 != i6 &&
                  i1 != i7 &&
                  i1 != i8 &&
                  i2 != i3 &&
                  i2 != i4 &&
                  i2 != i5 &&
                  i2 != i6 &&
                  i2 != i7 &&
                  i2 != i8 &&
                  i3 != i4 &&
                  i3 != i5 &&
                  i3 != i6 &&
                  i3 != i7 &&
                  i3 != i8 &&
                  i4 != i5 &&
                  i4 != i6 &&
                  i4 != i7 &&
                  i4 != i8 &&
                  i5 != i6 &&
                  i5 != i7 &&
                  i5 != i8 &&
                  i6 != i7 &&
                  i6 != i8 &&
                  i7 != i8
                ) {
                  path[counter] = 
                    i1 +
                    1 +
                    " → " +
                    (i2 + 1) +
                    " → " +
                    (i3 + 1) +
                    " → " +
                    (i4 + 1) +
                    " → " +
                    (i5 + 1) +
                    " → " +
                    (i6 + 1) +
                    " → " +
                    (i7 + 1) +
                    " → " +
                    (i8 + 1);
                  console.log(path[counter]);
                  if (
                    towns[i1][i2] +
                      towns[i2][i3] +
                      towns[i3][i4] +
                      towns[i4][i5] +
                      towns[i5][i6] +
                      towns[i6][i7] +
                      towns[i7][i8] <
                    minPath
                  ) {
                    minPath = 
                      towns[i1][i2] +
                      towns[i2][i3] +
                      towns[i3][i4] +
                      towns[i4][i5] +
                      towns[i5][i6] +
                      towns[i6][i7] +
                      towns[i7][i8];
                    console.log(minPath);
                    minCounter = counter;
                  }
                  counter += 1;
                }
              }
            }
          }
        }
      }
    }
  }
}

console.log(
  "Shortest Way: " +
    path[minCounter] +
    "(" +
    minPath +
    " KM.)"
);

修改方案

一、Python代码修改(支持非闭合路径)

原代码核心是生成闭合回路,需去掉回到起点的逻辑,具体修改如下:

  1. 路径长度计算修改
    删除原代码中添加回到起点的路径长度部分,只计算线性路径的相邻节点距离和:
# 替换原路径长度计算代码
for i in range(0, len(result)-1, 2):
    PathLenght += StartMatrix[result[i]-1][result[i+1]-1]
  1. 路径输出修改
    原result数组是闭合回路的节点对,需移除最后一个回到起点的节点对,生成线性路径:
# 在生成result后添加
if len(result) >= 2:
    result = result[:-2]  # 移除最后一步回到起点的节点对
print(result)
  1. 可选:指定固定起点和终点
    若需固定起点S和终点E,可在输入阶段增加参数,并限制闭环路径:
# 添加起点终点输入
start = int(input("请输入起点编号:")) - 1
end = int(input("请输入终点编号:")) - 1

# 禁止从终点回到起点,避免闭环
matrix[end][start] = float('inf')

二、JavaScript代码修改(支持非闭合路径)

原JS代码的全排列逻辑本身已计算线性路径(无回到起点步骤),只需优化为指定固定起点和终点即可:

  1. 固定起点和终点
    比如指定起点为1(索引0)、终点为8(索引7),修改循环条件:
// 固定起点为索引0
for (let i1 = 0; i1 <= 0; i1++) {
    // ...保留中间循环逻辑
    // 固定终点为索引7
    for (let i8 = 7; i8 <=7; i8++) {
        // 保留原节点不重复判断
        if (
          i1 != i2 && i1 != i3 && ... && i7 != i8
        ) {
            // 原逻辑不变
        }
    }
}
  1. 通用化递归实现
    将多层嵌套循环改为递归,适配任意数量节点的非闭合路径求解:
function findShortestPath(towns, startIdx, endIdx) {
    let path = [];
    let minPath = Infinity;
    let bestPath = "";
    let n = towns.length;

    function permute(current, used) {
        if (current.length === n) {
            if (current[0] === startIdx && current[n-1] === endIdx) {
                let currentPath = current.map(i => i+1).join(" → ");
                let currentLength = 0;
                for (let i = 0; i < n-1; i++) {
                    currentLength += towns[current[i]][current[i+1]];
                }
                if (currentLength < minPath) {
                    minPath = currentLength;
                    bestPath = currentPath;
                }
            }
            return;
        }
        for (let i = 0; i < n; i++) {
            if (!used[i]) {
                used[i] = true;
                permute([...current, i], used);
                used[i] = false;
            }
        }
    }

    permute([], Array(n).fill(false));
    return { path: bestPath, length: minPath };
}

// 调用示例:起点1(索引0),终点8(索引7)
let result = findShortestPath(towns, 0, 7);
console.log(`Shortest Way: ${result.path} (${result.length} KM.)`);

内容的提问来源于stack exchange,提问作者Akira Frank

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.19 15:30:43