- 算法设计与分析
- 首页
- 算法基础
- DAA - 算法导论
- DAA - 算法分析
- DAA - 分析方法
- DAA - 渐进符号与先验分析
- DAA - 时间复杂度
- DAA - 主定理
- DAA - 空间复杂度
- 分治法
- DAA - 分治算法
- DAA - 最大最小问题
- DAA - 归并排序算法
- DAA - Strassen矩阵乘法
- DAA - Karatsuba算法
- DAA - 汉诺塔
- 贪心算法
- DAA - 贪心算法
- DAA - 旅行商问题
- DAA - Prim最小生成树
- DAA - Kruskal最小生成树
- DAA - Dijkstra最短路径算法
- DAA - 地图着色算法
- DAA - 分数背包问题
- DAA - 带截止日期的作业调度
- DAA - 最佳合并模式
- 动态规划
- DAA - 动态规划
- DAA - 矩阵链乘法
- DAA - Floyd-Warshall算法
- DAA - 0-1背包问题
- DAA - 最长公共子序列算法
- DAA - 使用动态规划的旅行商问题
- 随机算法
- DAA - 随机算法
- DAA - 随机快速排序算法
- DAA - Karger最小割算法
- DAA - Fisher-Yates洗牌算法
- 近似算法
- DAA - 近似算法
- DAA - 顶点覆盖问题
- DAA - 集合覆盖问题
- DAA - 旅行商问题的近似算法
- 排序技术
- DAA - 冒泡排序算法
- DAA - 插入排序算法
- DAA - 选择排序算法
- DAA - 希尔排序算法
- DAA - 堆排序算法
- DAA - 桶排序算法
- DAA - 计数排序算法
- DAA - 基数排序算法
- DAA - 快速排序算法
- 搜索技术
- DAA - 搜索技术导论
- DAA - 线性搜索
- DAA - 二分搜索
- DAA - 插值搜索
- DAA - 跳跃搜索
- DAA - 指数搜索
- DAA - 斐波那契搜索
- DAA - 子列表搜索
- DAA - 哈希表
- 图论
- DAA - 最短路径
- DAA - 多阶段图
- DAA - 最佳成本二叉搜索树
- 堆算法
- DAA - 二叉堆
- DAA - 插入方法
- DAA - 堆化方法
- DAA - 提取方法
- 复杂度理论
- DAA - 确定性与非确定性计算
- DAA - 最大团
- DAA - 顶点覆盖
- DAA - P类与NP类
- DAA - 库克定理
- DAA - NP难与NP完全类
- DAA - 爬山算法
- DAA有用资源
- DAA - 快速指南
- DAA - 有用资源
- DAA - 讨论
爬山算法
前面章节中讨论的算法都是系统地运行的。为了达到目标,需要存储一个或多个之前探索过的路径来找到最优解。
对于许多问题,通往目标的路径并不重要。例如,在N皇后问题中,我们不需要关心皇后的最终配置,也不需要关心皇后的添加顺序。
爬山法
爬山法是一种解决某些优化问题的技术。在这种技术中,我们从一个次优解开始,并反复改进解,直到某个条件最大化。
从次优解开始的想法类似于从山脚下开始,改进解类似于沿着山坡向上行走,最后最大化某个条件类似于到达山顶。
因此,爬山法可以被认为包括以下阶段:
- 构造一个满足问题约束的次优解
- 逐步改进解
- 改进解,直到无法再改进
爬山法主要用于解决计算复杂的问题。它只关注当前状态和直接的未来状态。因此,这种技术在内存方面效率很高,因为它不维护搜索树。
算法
Evaluate the initial state. Loop until a solution is found or there are no new operators left to be applied: - Select and apply a new operator - Evaluate the new state: goal -→ quit better than current state -→ new current state
迭代改进
在迭代改进方法中,通过每次迭代都朝着最优解的方向前进,从而达到最优解。但是,这种技术可能会遇到局部最大值。在这种情况下,没有附近的更好的解的状态。
这个问题可以通过不同的方法来避免。其中一种方法是模拟退火。
随机重启
这是解决局部最优问题另一种方法。该技术进行一系列搜索。每次搜索都从随机生成的初始状态开始。因此,通过比较搜索的结果,可以得到最优解或接近最优解。
爬山法的局限性
局部最大值
如果启发式函数不是凸函数,则爬山法可能会收敛到局部最大值,而不是全局最大值。
山脊和山谷
如果目标函数创建了一个狭窄的山脊,那么爬山者只能通过之字形的方式才能向上攀登山脊或向下进入山谷。在这种情况下,爬山者需要采取非常小的步骤,需要更多时间才能到达目标。
高原
当搜索空间是平坦的或足够平坦时,由于机器用来表示其值的精度,目标函数返回的值与附近区域返回的值无法区分,就会遇到高原。
爬山法的复杂度
这种技术不会遇到与空间相关的問題,因为它只关注当前状态。之前探索过的路径不会被存储。
对于随机重启爬山法中的大多数问题,可以在多项式时间内获得最优解。但是,对于NP完全问题,计算时间可能会随着局部最大值的个数呈指数增长。
爬山法的应用
爬山法可以用来解决许多问题,在这些问题中,当前状态允许使用精确的评估函数,例如网络流问题、旅行商问题、8皇后问题、集成电路设计等。
爬山法也用于归纳学习方法中。该技术在机器人技术中用于协调团队中多个机器人的协作。还有许多其他问题也使用了这种技术。
示例
该技术可以应用于解决旅行商问题。首先确定一个初始解,该解恰好访问所有城市一次。因此,这个初始解在大多数情况下都不是最优的。即使这个解也可能非常糟糕。爬山算法从这样的初始解开始,并以迭代的方式对其进行改进。最终,很可能获得一条更短的路线。
以下是上述方法在各种编程语言中的实现:
#include <stdio.h> #include <stdlib.h> #include <time.h> #define NUM_CITIES 4 // Distance matrix representing distances between cities // Replace this with the actual distance matrix for your problem int distance_matrix[NUM_CITIES][NUM_CITIES] = { {0, 10, 15, 20}, {10, 0, 35, 25}, {15, 35, 0, 30}, {20, 25, 30, 0} }; int total_distance(int* path, int num_cities) { // Calculate the total distance traveled in the given path int total = 0; for (int i = 0; i < num_cities - 1; i++) { total += distance_matrix[path[i]][path[i + 1]]; } total += distance_matrix[path[num_cities - 1]][path[0]]; // Return to starting city return total; } void hill_climbing_tsp(int num_cities, int max_iterations) { int current_path[NUM_CITIES]; // Initial solution, visiting cities in order for (int i = 0; i < num_cities; i++) { current_path[i] = i; } int current_distance = total_distance(current_path, num_cities); for (int it = 0; it < max_iterations; it++) { // Generate a neighboring solution by swapping two random cities int neighbor_path[NUM_CITIES]; for (int i = 0; i < num_cities; i++) { neighbor_path[i] = current_path[i]; } int i = rand() % num_cities; int j = rand() % num_cities; int temp = neighbor_path[i]; neighbor_path[i] = neighbor_path[j]; neighbor_path[j] = temp; int neighbor_distance = total_distance(neighbor_path, num_cities); // If the neighbor solution is better, move to it if (neighbor_distance < current_distance) { for (int i = 0; i < num_cities; i++) { current_path[i] = neighbor_path[i]; } current_distance = neighbor_distance; } } printf("Optimal path: "); for (int i = 0; i < num_cities; i++) { printf("%d ", current_path[i]); } printf("\nTotal distance: %d\n", current_distance); } int main() { srand(time(NULL)); int max_iterations = 10000; hill_climbing_tsp(NUM_CITIES, max_iterations); return 0; }
输出
Optimal path: 1 0 2 3 Total distance: 80
#include <iostream> #include <vector> #include <algorithm> #include <ctime> #include <cstdlib> using namespace std; #define NUM_CITIES 4 // Distance matrix representing distances between cities // Replace this with the actual distance matrix for your problem int distance_matrix[NUM_CITIES][NUM_CITIES] = { {0, 10, 15, 20}, {10, 0, 35, 25}, {15, 35, 0, 30}, {20, 25, 30, 0} }; int total_distance(const std::vector<int>& path) { // Calculate the total distance traveled in the given path int total = 0; for (size_t i = 0; i < path.size() - 1; i++) { total += distance_matrix[path[i]][path[i + 1]]; } total += distance_matrix[path.back()][path[0]]; // Return to starting city return total; } void hill_climbing_tsp(int num_cities, int max_iterations) { vector<int> current_path(num_cities); // Initial solution, visiting cities in order for (int i = 0; i < num_cities; i++) { current_path[i] = i; } int current_distance = total_distance(current_path); for (int it = 0; it < max_iterations; it++) { // Generate a neighboring solution by swapping two random cities std::vector<int> neighbor_path = current_path; int i = rand() % num_cities; int j = rand() % num_cities; swap(neighbor_path[i], neighbor_path[j]); int neighbor_distance = total_distance(neighbor_path); // If the neighbor solution is better, move to it if (neighbor_distance < current_distance) { current_path = neighbor_path; current_distance = neighbor_distance; } } cout << "Optimal path: "; for (int city : current_path) { cout << city << " "; } cout << endl; cout << "Total distance: " << current_distance << endl; } int main() { srand(time(NULL)); int max_iterations = 10000; hill_climbing_tsp(NUM_CITIES, max_iterations); return 0; }
输出
Optimal path: 0 1 3 2 Total distance: 80
import java.util.ArrayList; import java.util.List; import java.util.Random; public class HillClimbingTSP { private static final int NUM_CITIES = 4; // Distance matrix representing distances between cities // Replace this with the actual distance matrix for your problem private static final int[][] distanceMatrix = { {0, 10, 15, 20}, {10, 0, 35, 25}, {15, 35, 0, 30}, {20, 25, 30, 0} }; private static int totalDistance(List<Integer> path) { // Calculate the total distance traveled in the given path int total = 0; for (int i = 0; i < path.size() - 1; i++) { total += distanceMatrix[path.get(i)][path.get(i + 1)]; } total += distanceMatrix[path.get(path.size() - 1)][path.get(0)]; // Return to starting city return total; } private static List<Integer> generateRandomPath(int numCities) { List<Integer> path = new ArrayList<>(); for (int i = 0; i < numCities; i++) { path.add(i); } Random rand = new Random(); for (int i = numCities - 1; i > 0; i--) { int j = rand.nextInt(i + 1); int temp = path.get(i); path.set(i, path.get(j)); path.set(j, temp); } return path; } public static void hillClimbingTSP(int numCities, int maxIterations) { List<Integer> currentPath = generateRandomPath(numCities); // Initial solution int currentDistance = totalDistance(currentPath); for (int it = 0; it < maxIterations; it++) { // Generate a neighboring solution by swapping two random cities List<Integer> neighborPath = new ArrayList<>(currentPath); int i = new Random().nextInt(numCities); int j = new Random().nextInt(numCities); int temp = neighborPath.get(i); neighborPath.set(i, neighborPath.get(j)); neighborPath.set(j, temp); int neighborDistance = totalDistance(neighborPath); // If the neighbor solution is better, move to it if (neighborDistance < currentDistance) { currentPath = neighborPath; currentDistance = neighborDistance; } } System.out.print("Optimal path: "); for (int city : currentPath) { System.out.print(city + " "); } System.out.println(); System.out.println("Total distance: " + currentDistance); } public static void main(String[] args) { int maxIterations = 10000; hillClimbingTSP(NUM_CITIES, maxIterations); } }
输出
Optimal path: 1 3 2 0 Total distance: 80
import random # Distance matrix representing distances between cities # Replace this with the actual distance matrix for your problem distance_matrix = [ [0, 10, 15, 20], [10, 0, 35, 25], [15, 35, 0, 30], [20, 25, 30, 0] ] def total_distance(path): # Calculate the total distance traveled in the given path total = 0 for i in range(len(path) - 1): total += distance_matrix[path[i]][path[i+1]] total += distance_matrix[path[-1]][path[0]] # Return to starting city return total def hill_climbing_tsp(num_cities, max_iterations=10000): current_path = list(range(num_cities)) # Initial solution, visiting cities in order current_distance = total_distance(current_path) for _ in range(max_iterations): # Generate a neighboring solution by swapping two random cities neighbor_path = current_path.copy() i, j = random.sample(range(num_cities), 2) neighbor_path[i], neighbor_path[j] = neighbor_path[j], neighbor_path[i] neighbor_distance = total_distance(neighbor_path) # If the neighbor solution is better, move to it if neighbor_distance < current_distance: current_path = neighbor_path current_distance = neighbor_distance return current_path def main(): num_cities = 4 # Number of cities in the TSP solution = hill_climbing_tsp(num_cities) print("Optimal path:", solution) print("Total distance:", total_distance(solution)) if __name__ == "__main__": main()
输出
Optimal path: [1, 0, 2, 3] Total distance: 80