1. 程式人生 > 其它 >最小生成樹演算法求解TSP

最小生成樹演算法求解TSP

最小生成樹求解TSP問題

步驟:

首先根據輸入生成TSP地圖資料,然後利用克魯斯卡爾(Kruskal)和普利姆(prim)演算法求解這個TSP問題,最後用圖畫出來。

演算法思想:

克魯斯卡爾演算法的核心思想是:在帶權連通圖中,不斷地在邊集合中找到最小的邊,如果該邊滿足得到最小生成樹的條件,就將其構造,直到最後得到一顆最小生成樹

普利姆演算法的核心步驟是:在帶權連通圖中,從圖中某一頂點v開始,此時集合U={v},重複執行下述操作:在所有u∈U,w∈V-U的邊(u,w)∈E中找到一條權值最小的邊,將(u,w)這條邊加入到已找到邊的集合,並且將點w加入到集合U中,當U=V時,就找到了這顆最小生成樹。

演算法程式碼(python)

Kruskal

# kruskal
edge_count = 0
for i in range(size):
    for j in range(i):
        if 0 < distance[i][j] < 999998:
            edge_count += 1
kruskal_list = []
edge_list = []

for i in range(size):
    for j in range(i+1, size):
        edge_list.append([i, j, distance[i][j]])
edge_list.sort(key=lambda a: a[2])

group = [[i] for i in range(size)]
for edge in edge_list:
    for i in range(len(group)):
        if edge[0] in group[i]:
            m = i
        if edge[1] in group[i]:
            n = i
    if m != n:
        kruskal_list.append(edge)
        group[m] = group[m] + group[n]
        group[n] = []

Prim

# Prim
prim_list = []

selected_node = [0]
candidate_node = [i for i in range(1, size)]
while len(candidate_node) > 0 :
    min_dis = 999998
    for i in selected_node:
        for j in candidate_node:
            if distance[i][j] < min_dis:
                min_dis = distance[i][j]
                cur_node = i
                next_select_node = j
    prim_list.append([cur_node, next_select_node, min_dis])
    selected_node.append(next_select_node)
    candidate_node.remove(next_select_node)

程式碼測試:

(1)
15個城市迅速收斂



(2)
100個城市可以快速收斂

(3)

1000個城市無法快速收斂

原始碼:

import numpy as np
import matplotlib.pyplot as plt

size = int(input("城市個數:"))
scale = int(input("比例尺:"))
MAX_ = 999999
coord = []
distance = np.zeros((size, size))

i = 0
while i < size:
    x = np.random.rand() * scale
    y = np.random.rand() * scale
    if [x, y] not in coord:
        coord.append([x, y])
        i = i + 1
coord = np.array(coord)

for i in range(size):
    for j in range(size):
        if i == j :
            distance[i][j] = MAX_
        else:
            distance[i][j] = distance[j][i] = np.linalg.norm(coord[i] - coord[j])

# kruskal
edge_count = 0
for i in range(size):
    for j in range(i):
        if 0 < distance[i][j] < 999998:
            edge_count += 1
kruskal_list = []
edge_list = []

for i in range(size):
    for j in range(i+1, size):
        edge_list.append([i, j, distance[i][j]])
edge_list.sort(key=lambda a: a[2])

group = [[i] for i in range(size)]
for edge in edge_list:
    for i in range(len(group)):
        if edge[0] in group[i]:
            m = i
        if edge[1] in group[i]:
            n = i
    if m != n:
        kruskal_list.append(edge)
        group[m] = group[m] + group[n]
        group[n] = []

# Prim
prim_list = []

selected_node = [0]
candidate_node = [i for i in range(1, size)]
while len(candidate_node) > 0 :
    min_dis = 999998
    for i in selected_node:
        for j in candidate_node:
            if distance[i][j] < min_dis:
                min_dis = distance[i][j]
                cur_node = i
                next_select_node = j
    prim_list.append([cur_node, next_select_node, min_dis])
    selected_node.append(next_select_node)
    candidate_node.remove(next_select_node)

print(coord)
print(distance)
print("----------------------Kruskal-----------------------")
print(np.array(kruskal_list))
print("----------------------Prim-----------------------")
print(np.array(prim_list))

fig = plt.figure(1, (45, 15))
ax1 = fig.add_subplot(131)
ax1.set_title("MAP{}".format(size))
ax1.plot(coord[:, 0], coord[:, 1], 'o')

ax2 = fig.add_subplot(132)
ax2.set_title("Kruskal")
x = []
y = []
for t_list in kruskal_list:
    ax2.plot([coord[t_list[0], 0], coord[t_list[1], 0]], [coord[t_list[0], 1], coord[t_list[1], 1]])

ax3 = fig.add_subplot(133)
ax3.set_title("Prim")
for t_list in prim_list:
    ax3.plot([coord[t_list[0], 0], coord[t_list[1], 0]], [coord[t_list[0], 1], coord[t_list[1], 1]])

plt.show()