深度優先搜尋演算法求解TSP問題

2021-09-22 19:47:47 字數 4380 閱讀 8765

**【問題描述】**採用深度優先搜尋演算法求解tsp問題,並在搜尋過程中,使用界限條件(當前結點已經走過的路徑長度要小於已求得的最短路徑)進行「剪枝」操作(不再對後續結點進行遍歷),從而提高搜尋效率。採用queue模組中的棧(lifoqueue)來實現深度優先搜尋。

**【輸入形式】**在螢幕上輸入頂點個數和連線頂點間的邊的鄰接矩陣。

**【輸出形式】**最優值和其中一條最優路徑。

【樣例輸入】

0 30 6 4

30 0 5 10

6 5 0 20

4 10 20 0

【樣例輸出】

[1][1, 2]

[1, 2, 3]

[1, 2, 3, 4]

[1, 2, 4]

[1, 3]

[1, 3, 2]

[1, 3, 2, 4]

[1, 3, 4]

[1, 4]

[1, 4, 2]

[1, 4, 2, 3]

[1, 4, 3]

25: [1, 3, 2, 4]

【樣例說明】

輸入:頂點個數為4。連線頂點間邊的鄰接矩陣大小為4行4列,位置[i,j]上元素值表示第i個頂點到第j個頂點的距離,0表示兩個頂點間沒有邊連線。

輸出:最優值為25,最優路徑為[1, 3, 2, 4]。

**【評分標準】**根據輸入得到準確的輸出。

python實現:

import math  # 回溯法求解旅行商問題

'''path中最開始只有源點1,對頂點按照從小到大的全排列順序乙個乙個判斷是否到達葉子節點時,再回到源點有最短路徑

深度優先搜尋,模擬解答樹過程

'''bestcost = math.inf # 最短路徑

nowcost = 0 # 當前的路徑長度

x = [1, 2, 3, 4, 5, 6] # 頂點序號

path = [1] # 模擬open表中過程

arc = # 存放

def main():

n = int(input()) # 頂點個數

graph = # 圖的鄰接矩陣

for i in range(n):

tsp(graph, 1, n)

print(bestcost, end=": ")

print(arc[:n])

def tsp(graph, s, n): # 深度優先搜尋,模擬解答樹過程

global nowcost, bestcost, arc

print(path)

if s == n:

if graph[x[n - 1]-1][x[0]-1] != 0 and (nowcost + graph[x[n - 1]-1][x[0]-1] < bestcost):

arc = x[:]

# print("arc", arc)

bestcost = nowcost + graph[x[n - 1]-1][x[0]-1]

# print('bestcost', bestcost)

else:

for i in range(s, n):

# 求得的值大於目前的最佳值的放棄搜尋,「剪枝」

if graph[x[i - 1]-1][x[i]-1] != 0 and nowcost + graph[x[i - 1]-1][x[i]-1] < bestcost:

x.insert(s, x[i]) # 從小到大生成全排列的過程

del x[i+1]

# x.remove(x[i+1]) # 這樣刪除結果有錯誤,為啥

# x[i], x[s] = x[s], x[i] # 全排列

# print(x)

nowcost += graph[x[s - 1]-1][x[s]-1] # 將花費加入

tsp(graph, s+1, n)

nowcost -= graph[x[s - 1]-1][x[s]-1] # 回溯上去還需要減去

path.remove(x[s])

# x[i], x[s] = x[s], x[i] # 這樣的全排列不是從小到大的

x.insert(i+1, x[s])

del x[s]

# x.remove(x[s]) # 這樣刪除結果錯誤,為啥

if __name__ == '__main__':

main()

'''樣例輸入

40 30 6 4

30 0 5 10

6 5 0 20

4 10 20 0

'''

列表刪除那裡的錯誤原因:

remove(value)

del(index)

也就是說兩個刪除函式的引數意義不同,注意區分。

import numpy as np

import queue as q

class vertexnode(object): # 頂點類

def __init__(self, path=none, cost=none):

self.path = path # 到當前結點為止已經走過的路徑

self.cost = cost # 到當前結點為止的費用

def tst_dfs(w_array, s_index):

# 初始化最優值和最優路徑

best_cost = np.inf

best_path = none

vex_num, _ = w_array.shape

# 初始化起點結點和棧,將起始節點加入棧

start_node = vertexnode(path=[s_index], cost=0)

open_queue = q.lifoqueue()

open_queue.put(start_node)

# 當棧中非空時,迴圈

while not open_queue.empty():

cur_node = open_queue.get()

print(cur_node.path)

# 如果當前結點的費用大於最優值,則無需進行擴充套件或者判斷

if cur_node.cost >= best_cost:

continue

# 如果當前結點已經為葉結點,則判斷當前結點費用加上回到起始點的 # 費用和是否小於最優值,若是則替換

# 判斷結束後,跳過後續程式,直接執行下一迴圈

if len(cur_node.path) == vex_num:

new_cost = cur_node.cost + w_array[cur_node.path[-1]-1, s_index-1]

if new_cost < best_cost:

best_cost = new_cost

best_path = list(cur_node.path)

continue

# 當前結點非葉子節點,則擴充套件當前結點,將加新節點到棧中

for i in range(vex_num, 0, -1):

if not(i in cur_node.path):

new_cost = cur_node.cost + w_array[cur_node.path[-1]-1, i-1]

# 當新節點的費用小於最優值時,才將新結點加入到棧中,否則執行剪枝操作

if new_cost < best_cost:

new_path = list(cur_node.path)

new_node = vertexnode(path=new_path, cost=new_cost)

open_queue.put(new_node)

return best_cost, best_path

def main():

vex_num = int(input()) # 頂點個數

w_array = np.zeros((vex_num, vex_num), dtype=np.double) # 鄰接矩陣

for i in range(vex_num):

w_array[i, :] = np.array(input().split(), dtype=np.double)

w_array[w_array == 0] = np.inf

s_index = 1 # 起始點序號

best_cost, best_path = tst_dfs(w_array, s_index)

print('{}: {}'.format(int(best_cost), best_path))

if __name__ == '__main__':

main()

禁忌搜尋演算法求解TSP

本文的禁忌搜尋演算法是最經典禁忌搜尋演算法,可以在此基礎上進行修改和擴充套件 主函式 author chauncy xu date 2020年4月1日 clc clear all close all len side,city city num city size city,1 城市數目 gen 1...

深度優先搜尋演算法

include include define vertexnum 9 struct node typedef struct node graph struct node head vertexnum 定義圖形結構 int visited vertexnum 頂點陣列 深度優先搜尋 void dfs ...

深度優先搜尋演算法

今天我們來複習一下萬能的搜尋演算法之深度優先搜尋演算法。深度優先搜尋演算法顧名思義就是按照樹的延伸不停的往下搜尋,直到樹的盡頭之後再一步一步的回溯回來。好吧,我們直接問你乙個問題,給你乙個數n,讓你輸出從1到這個樹的全排列,你會怎麼寫,會不會想到去用若干個for迴圈?好吧,你肯定錯了,其實他考的就是...