- 算法设计与分析
- 家
- 算法基础知识
- DAA - 简介
- DAA - 算法分析
- DAA-分析方法
- 渐近符号和先验分析
- 时间复杂度
- 马斯特定理
- DAA - 空间复杂性
- 分而治之
- DAA-分而治之
- DAA - 最大最小问题
- DAA-归并排序
- DAA-二分查找
- 施特拉森矩阵乘法
- 唐叶算法
- 河内塔
- 贪心算法
- DAA-贪婪法
- 旅行商问题
- Prim 的最小生成树
- 克鲁斯卡尔的最小生成树
- Dijkstra 的最短路径算法
- 地图着色算法
- DAA-分数背包
- DAA - 带截止日期的作业排序
- DAA - 最佳合并模式
- 动态规划
- DAA-动态规划
- 矩阵链乘法
- 弗洛伊德·沃歇尔算法
- DAA - 0-1 背包
- 最长公共子序列
- 旅行商问题| 动态规划
- 随机算法
- 随机算法
- 随机快速排序
- 卡格的最低削减
- 费舍尔-耶茨洗牌
- 近似算法
- 近似算法
- 顶点覆盖问题
- 设置封面问题
- 旅行推销员近似算法
- 排序技巧
- DAA-快速排序
- DAA-冒泡排序
- DAA——插入排序
- DAA-选择排序
- DAA——希尔排序
- DAA-堆排序
- DAA——桶排序
- DAA——计数排序
- DAA - 基数排序
- 搜索技巧
- 搜索技术介绍
- DAA - 线性搜索
- DAA-二分查找
- DAA - 插值搜索
- DAA - 跳转搜索
- DAA - 指数搜索
- DAA - 斐波那契搜索
- DAA - 子列表搜索
- DAA-哈希表
- 图论
- DAA-最短路径
- DAA - 多级图
- 最优成本二叉搜索树
- 堆算法
- DAA-二叉堆
- DAA-插入法
- DAA-Heapify 方法
- DAA-提取方法
- 复杂性理论
- 确定性计算与非确定性计算
- DAA-最大派系
- DAA - 顶点覆盖
- DAA - P 级和 NP 级
- DAA-库克定理
- NP 硬课程和 NP 完全课程
- DAA - 爬山算法
- DAA 有用资源
- DAA - 快速指南
- DAA - 有用的资源
- DAA - 讨论
旅行推销员近似算法
我们已经使用贪心和动态规划方法讨论了旅行商问题,并且确定在多项式时间内解决旅行商问题以获得完美的最优解是不可能的。
因此,近似解有望找到该 NP-Hard 问题的接近最优解。然而,只有当问题中的成本函数(定义为两个绘制点之间的距离)满足三角不等式时,才会设计近似算法。
仅当三角形 u、v 和 w 的所有顶点的成本函数 c 满足以下方程时,三角形不等式才成立
c(u, w)≤ c(u, v)+c(v, w)
在许多应用中它通常会自动满足。
旅行推销员近似算法
旅行推销员近似算法需要执行一些先决算法,以便我们可以获得接近最优的解决方案。让我们简单地看一下这些先决条件算法 -
最小生成树- 最小生成树是一种树数据结构,包含主图的所有顶点,并且连接它们的边数最少。在这种情况下,我们将 prim 算法应用于最小生成树。
前序遍历- 前序遍历是在树数据结构上完成的,其中指针按 [根 - 左子 - 右子] 顺序遍历树的所有节点。
算法
步骤 1 - 随机选择给定图的任何顶点作为起点和终点。
步骤 2 - 使用 prim 算法构建图的最小生成树,并选择顶点作为根。
步骤 3 - 一旦构建了生成树,就对上一步中获得的最小生成树执行前序遍历。
步骤 4 - 获得的预购解是旅行推销员的哈密顿路径。
伪代码
APPROX_TSP(G, c) r <- root node of the minimum spanning tree T <- MST_Prim(G, c, r) visited = {ф} for i in range V: H <- Preorder_Traversal(G) visited = {H}
分析
如果满足三角不等式,旅行商问题的逼近算法就是2-逼近算法。
为了证明这一点,我们需要证明问题的近似成本是最优成本的两倍。支持这一说法的观察结果如下:
最小生成树的成本永远不会小于最优哈密顿路径的成本。即,c(M)≤c(H * )。
全步行的成本也是最小生成树成本的两倍。完整行走被定义为预序遍历最小生成树时所追踪的路径。完整步行遍历图中存在的每条边恰好两次。因此,c(W) = 2c(T)
由于预序行走路径小于全行走路径,因此算法的输出总是低于全行走的成本。
例子
让我们看一个示例图来可视化这个近似算法 -
解决方案
将上图中的顶点 1 视为旅行推销员的起点和终点,并从这里开始算法。
步骤1
从顶点 1 开始算法,从图中构造最小生成树。要了解有关构建最小生成树的更多信息,请单击此处。
第2步
一旦构建了最小生成树,就将起始顶点视为根节点(即顶点1)并按顺序遍历生成树。
旋转生成树以便于解释,我们得到 -
发现树的前序遍历为 − 1 → 2 → 5 → 6 → 3 → 4
步骤3
将根节点添加到跟踪路径的末尾,我们得到1 → 2 → 5 → 6 → 3 → 4 → 1
这是旅行商近似问题的输出哈密顿路径。路径的成本将是最小生成树中所有成本的总和,即55。
例子
#include <stdio.h> #include <stdbool.h> #include <limits.h> #define V 6 // Number of vertices in the graph // Function to find the minimum key vertex from the set of vertices not yet included in MST int findMinKey(int key[], bool mstSet[]) { int min = INT_MAX, min_index; for (int v = 0; v < V; v++) { if (mstSet[v] == false && key[v] < min) { min = key[v]; min_index = v; } } return min_index; } // Function to perform Prim's algorithm to find the Minimum Spanning Tree (MST) void primMST(int graph[V][V], int parent[]) { int key[V]; bool mstSet[V]; for (int i = 0; i < V; i++) { key[i] = INT_MAX; mstSet[i] = false; } key[0] = 0; parent[0] = -1; for (int count = 0; count < V - 1; count++) { int u = findMinKey(key, mstSet); mstSet[u] = true; for (int v = 0; v < V; v++) { if (graph[u][v] && mstSet[v] == false && graph[u][v] < key[v]) { parent[v] = u; key[v] = graph[u][v]; } } } } // Function to print the preorder traversal of the Minimum Spanning Tree void printPreorderTraversal(int parent[]) { printf("The preorder traversal of the tree is found to be − "); for (int i = 1; i < V; i++) { printf("%d → ", parent[i]); } printf("\n"); } // Main function for the Traveling Salesperson Approximation Algorithm void tspApproximation(int graph[V][V]) { int parent[V]; int root = 0; // Choosing vertex 0 as the starting and ending point // Find the Minimum Spanning Tree using Prim's Algorithm primMST(graph, parent); // Print the preorder traversal of the Minimum Spanning Tree printPreorderTraversal(parent); // Print the Hamiltonian path (preorder traversal with the starting point added at the end) printf("Adding the root node at the end of the traced path "); for (int i = 0; i < V; i++) { printf("%d → ", parent[i]); } printf("%d → %d\n", root, parent[0]); // Calculate and print the cost of the Hamiltonian path int cost = 0; for (int i = 1; i < V; i++) { cost += graph[parent[i]][i]; } // The cost of the path would be the sum of all the costs in the minimum spanning tree. printf("Sum of all the costs in the minimum spanning tree %d.\n", cost); } int main() { // Example graph represented as an adjacency matrix int graph[V][V] = { {0, 3, 1, 6, 0, 0}, {3, 0, 5, 0, 3, 0}, {1, 5, 0, 5, 6, 4}, {6, 0, 5, 0, 0, 2}, {0, 3, 6, 0, 0, 6}, {0, 0, 4, 2, 6, 0} }; tspApproximation(graph); return 0; }
输出
The preorder traversal of the tree is found to be − 0 → 0 → 5 → 1 → 2 → Adding the root node at the end of the traced path -1 → 0 → 0 → 5 → 1 → 2 → 0 → -1 Sum of all the costs in the minimum spanning tree 13.
#include <iostream> #include <limits> #define V 6 // Number of vertices in the graph // Function to find the minimum key vertex from the set of vertices not yet included in MST int findMinKey(int key[], bool mstSet[]) { int min = std::numeric_limits<int>::max(); int min_index; for (int v = 0; v < V; v++) { if (mstSet[v] == false && key[v] < min) { min = key[v]; min_index = v; } } return min_index; } // Function to perform Prim's algorithm to find the Minimum Spanning Tree (MST) void primMST(int graph[V][V], int parent[]) { int key[V]; bool mstSet[V]; for (int i = 0; i < V; i++) { key[i] = std::numeric_limits<int>::max(); mstSet[i] = false; } key[0] = 0; parent[0] = -1; for (int count = 0; count < V - 1; count++) { int u = findMinKey(key, mstSet); mstSet[u] = true; for (int v = 0; v < V; v++) { if (graph[u][v] && mstSet[v] == false && graph[u][v] < key[v]) { parent[v] = u; key[v] = graph[u][v]; } } } } // Function to print the preorder traversal of the Minimum Spanning Tree void printPreorderTraversal(int parent[]) { std::cout << "The preorder traversal of the tree is found to be − "; for (int i = 1; i < V; i++) { std::cout << parent[i] << " → "; } std::cout << std::endl; } // Main function for the Traveling Salesperson Approximation Algorithm void tspApproximation(int graph[V][V]) { int parent[V]; int root = 0; // Choosing vertex 0 as the starting and ending point // Find the Minimum Spanning Tree using Prim's Algorithm primMST(graph, parent); // Print the preorder traversal of the Minimum Spanning Tree printPreorderTraversal(parent); // Print the Hamiltonian path (preorder traversal with the starting point added at the end) std::cout << "Adding the root node at the end of the traced path "; for (int i = 0; i < V; i++) { std::cout << parent[i] << " → "; } std::cout << root << " → " << parent[0] << std::endl; // Calculate and print the cost of the Hamiltonian path int cost = 0; for (int i = 1; i < V; i++) { cost += graph[parent[i]][i]; } // The cost of the path would be the sum of all the costs in the minimum spanning tree. std::cout << "Sum of all the costs in the minimum spanning tree: " << cost << "." << std::endl; } int main() { // Example graph represented as an adjacency matrix int graph[V][V] = { {0, 3, 1, 6, 0, 0}, {3, 0, 5, 0, 3, 0}, {1, 5, 0, 5, 6, 4}, {6, 0, 5, 0, 0, 2}, {0, 3, 6, 0, 0, 6}, {0, 0, 4, 2, 6, 0} }; tspApproximation(graph); return 0; }
输出
The preorder traversal of the tree is found to be − 0 → 0 → 5 → 1 → 2 → Adding the root node at the end of the traced path -1 → 0 → 0 → 5 → 1 → 2 → 0 → -1 Sum of all the costs in the minimum spanning tree: 13.
import java.util.Arrays; public class TravelingSalesperson { static final int V = 6; // Number of vertices in the graph // Function to find the minimum key vertex from the set of vertices not yet included in MST static int findMinKey(int key[], boolean mstSet[]) { int min = Integer.MAX_VALUE; int minIndex = -1; for (int v = 0; v < V; v++) { if (!mstSet[v] && key[v] < min) { min = key[v]; minIndex = v; } } return minIndex; } // Function to perform Prim's algorithm to find the Minimum Spanning Tree (MST) static void primMST(int graph[][], int parent[]) { int key[] = new int[V]; boolean mstSet[] = new boolean[V]; Arrays.fill(key, Integer.MAX_VALUE); Arrays.fill(mstSet, false); key[0] = 0; parent[0] = -1; for (int count = 0; count < V - 1; count++) { int u = findMinKey(key, mstSet); mstSet[u] = true; for (int v = 0; v < V; v++) { if (graph[u][v] != 0 && !mstSet[v] && graph[u][v] < key[v]) { parent[v] = u; key[v] = graph[u][v]; } } } } // Function to print the preorder traversal of the Minimum Spanning Tree static void printPreorderTraversal(int parent[]) { System.out.print("The preorder traversal of the tree is found to be "); for (int i = 1; i < V; i++) { System.out.print(parent[i] + " -> "); } System.out.println(); } // Main function for the Traveling Salesperson Approximation Algorithm static void tspApproximation(int graph[][]) { int parent[] = new int[V]; int root = 0; // Choosing vertex 0 as the starting and ending point // Find the Minimum Spanning Tree using Prim's Algorithm primMST(graph, parent); // Print the preorder traversal of the Minimum Spanning Tree printPreorderTraversal(parent); // Print the Hamiltonian path (preorder traversal with the starting point added at the end) System.out.print("Adding the root node at the end of the traced path "); for (int i = 0; i < V; i++) { System.out.print(parent[i] + " -> "); } System.out.println(root + " " + parent[0]); // Calculate and print the cost of the Hamiltonian path int cost = 0; for (int i = 1; i < V; i++) { cost += graph[parent[i]][i]; } // The cost of the path would be the sum of all the costs in the minimum spanning tree. System.out.println("Sum of all the costs in the minimum spanning tree: " + cost); } public static void main(String[] args) { // Example graph represented as an adjacency matrix int graph[][] = { {0, 3, 1, 6, 0, 0}, {3, 0, 5, 0, 3, 0}, {1, 5, 0, 5, 6, 4}, {6, 0, 5, 0, 0, 2}, {0, 3, 6, 0, 0, 6}, {0, 0, 4, 2, 6, 0} }; tspApproximation(graph); } }
输出
The preorder traversal of the tree is found to be 0 -> 0 -> 5 -> 1 -> 2 -> Adding the root node at the end of the traced path -1 -> 0 -> 0 -> 5 -> 1 -> 2 -> 0 -1 Sum of all the costs in the minimum spanning tree: 13
import sys V = 6 # Number of vertices in the graph # Function to find the minimum key vertex from the set of vertices not yet included in MST def findMinKey(key, mstSet): min_val = sys.maxsize min_index = -1 for v in range(V): if not mstSet[v] and key[v] < min_val: min_val = key[v] min_index = v return min_index # Function to perform Prim's algorithm to find the Minimum Spanning Tree (MST) def primMST(graph, parent): key = [sys.maxsize] * V mstSet = [False] * V key[0] = 0 parent[0] = -1 for _ in range(V - 1): u = findMinKey(key, mstSet) mstSet[u] = True for v in range(V): if graph[u][v] and not mstSet[v] and graph[u][v] < key[v]: parent[v] = u key[v] = graph[u][v] # Function to print the preorder traversal of the Minimum Spanning Tree def printPreorderTraversal(parent): print("The preorder traversal of the tree is found to be − ", end="") for i in range(1, V): print(parent[i], " → ", end="") print() # Main function for the Traveling Salesperson Approximation Algorithm def tspApproximation(graph): parent = [0] * V root = 0 # Choosing vertex 0 as the starting and ending point # Find the Minimum Spanning Tree using Prim's Algorithm primMST(graph, parent) # Print the preorder traversal of the Minimum Spanning Tree printPreorderTraversal(parent) # Print the Hamiltonian path (preorder traversal with the starting point added at the end) print("Adding the root node at the end of the traced path ", end="") for i in range(V): print(parent[i], " → ", end="") print(root, " → ", parent[0]) # Calculate and print the cost of the Hamiltonian path cost = 0 for i in range(1, V): cost += graph[parent[i]][i] # The cost of the path would be the sum of all the costs in the minimum spanning tree. print("Sum of all the costs in the minimum spanning tree:", cost) if __name__ == "__main__": # Example graph represented as an adjacency matrix graph = [ [0, 3, 1, 6, 0, 0], [3, 0, 5, 0, 3, 0], [1, 5, 0, 5, 6, 4], [6, 0, 5, 0, 0, 2], [0, 3, 6, 0, 0, 6], [0, 0, 4, 2, 6, 0] ] tspApproximation(graph)
输出
The preorder traversal of the tree is found to be − 0 → 0 → 5 → 1 → 2 → Adding the root node at the end of the traced path -1 → 0 → 0 → 5 → 1 → 2 → 0 → -1 Sum of all the costs in the minimum spanning tree: 13