模拟退火算法(Simulated Annealing)是一种元启发式优化算法,通常用于解决组合优化问题,如旅行商问题、排课问题等。该算法的名称源于固体物质退火过程中的晶格结构变化。模拟退火算法模拟了晶体在高温下随机摆动、然后逐渐冷却以实现结晶过程的特点。
模拟退火算法的核心思想是通过在解空间中随机搜索,逐渐减小温度,以便在搜索过程中逐渐收敛到更优的解。算法允许在搜索过程中接受劣质解的概率,以避免陷入局部最优解。
虽然模拟退火算法不保证找到全局最优解,但它通常能够在合理的时间内找到较好的解决方案。它的性能受到参数设置、冷却计划和邻域搜索策略的影响,需要根据具体问题进行调优。这一算法在许多组合优化问题上都表现出色。
初始化:随机生成或者通过某种启发式方法产生一个初始解,这通常是问题的一个潜在解决方案。
冷却计划:定义一个温度下降的计划,以模拟冷却过程。通常,温度会从高到低逐渐降低。
迭代:在每个温度下,进行一定数量的迭代,每次迭代中,对当前解进行小的随机扰动,产生一个邻域解。
接受或拒绝邻域解:根据一定的概率策略,决定是否接受邻域解。通常,如果邻域解更好(即更小)或在一定概率内,会接受邻域解,否则拒绝。
降温:根据冷却计划,降低温度。
终止条件:根据一定的终止条件,例如达到最大迭代次数或温度降低到阈值以下,决定是否终止算法。
返回最佳解:返回在搜索过程中找到的最佳解。
0-1背包问题是经典的组合优化问题,目标是在给定背包容量下选择一组物品,使得它们的总价值最大,同时不超过背包的容量。
import java.util.Random;
public class SimulatedAnnealingKnapsackSolver {
private static final int NUM_ITERATIONS = 1000;
private static final double INITIAL_TEMPERATURE = 1000;
private static final double COOLING_RATE = 0.95;
public static void main(String[] args) {
int[] weights = {2, 5, 7, 3, 9};
int[] values = {7, 10, 13, 5, 15};
int maxWeight = 15;
int[] bestSolution = solveKnapsackProblem(weights, values, maxWeight);
int bestValue = calculateValue(bestSolution, values);
System.out.println("Best Solution: " + Arrays.toString(bestSolution));
System.out.println("Best Value: " + bestValue);
}
public static int[] solveKnapsackProblem(int[] weights, int[] values, int maxWeight) {
int[] currentSolution = generateRandomSolution(weights.length);
int[] bestSolution = currentSolution;
double temperature = INITIAL_TEMPERATURE;
for (int iteration = 0; iteration < NUM_ITERATIONS; iteration++) {
int[] neighborSolution = generateNeighborSolution(currentSolution);
int currentValue = calculateValue(currentSolution, values);
int neighborValue = calculateValue(neighborSolution, values);
int bestValue = calculateValue(bestSolution, values);
if (neighborValue > bestValue || Math.random() < acceptanceProbability(currentValue, neighborValue, temperature)) {
currentSolution = neighborSolution;
if (neighborValue > bestValue) {
bestSolution = neighborSolution;
}
}
temperature *= COOLING_RATE;
}
return bestSolution;
}
private static int[] generateRandomSolution(int length) {
int[] solution = new int[length];
Random random = new Random();
for (int i = 0; i < length; i++) {
solution[i] = random.nextInt(2); // 0 or 1
}
return solution;
}
private static int[] generateNeighborSolution(int[] solution) {
int[] neighbor = solution.clone();
Random random = new Random();
int index = random.nextInt(neighbor.length);
neighbor[index] = 1 - neighbor[index]; // Flip 0 to 1 or 1 to 0
return neighbor;
}
private static int calculateValue(int[] solution, int[] values) {
int value = 0;
for (int i = 0; i < solution.length; i++) {
value += solution[i] * values[i];
}
return value;
}
private static double acceptanceProbability(int currentValue, int neighborValue, double temperature) {
if (neighborValue > currentValue) {
return 1.0;
}
return Math.exp((neighborValue - currentValue) / temperature);
}
}
解决旅行商问题(Traveling Salesman Problem,TSP)是一个典型的组合优化问题,涉及寻找访问一组城市并返回起始城市的最短路径,使得每个城市仅访问一次。模拟退火算法可以用于寻找近似最优解。
使用一个简化的TSP问题,包含四个城市
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Random;
public class SimulatedAnnealingTSPSolver {
private static final int NUM_ITERATIONS = 1000;
private static final double INITIAL_TEMPERATURE = 1000;
private static final double COOLING_RATE = 0.95;
public static void main(String[] args) {
List<City> cities = new ArrayList<>();
cities.add(new City("A", 0, 0));
cities.add(new City("B", 2, 1));
cities.add(new City("C", 3, 3));
cities.add(new City("D", 1, 2));
List<City> bestTour = solveTSP(cities);
double bestTourLength = calculateTourLength(bestTour);
System.out.println("Best Tour: " + bestTour);
System.out.println("Best Tour Length: " + bestTourLength);
}
public static List<City> solveTSP(List<City> cities) {
List<City> currentTour = new ArrayList<>(cities);
Collections.shuffle(currentTour); // Random initial tour
List<City> bestTour = currentTour;
double temperature = INITIAL_TEMPERATURE;
for (int iteration = 0; iteration < NUM_ITERATIONS; iteration++) {
List<City> neighborTour = generateNeighborTour(currentTour);
double currentTourLength = calculateTourLength(currentTour);
double neighborTourLength = calculateTourLength(neighborTour);
if (neighborTourLength < currentTourLength || Math.random() < acceptanceProbability(currentTourLength, neighborTourLength, temperature)) {
currentTour = neighborTour;
if (neighborTourLength < calculateTourLength(bestTour)) {
bestTour = neighborTour;
}
}
temperature *= COOLING_RATE;
}
return bestTour;
}
private static List<City> generateNeighborTour(List<City> tour) {
List<City> neighbor = new ArrayList<>(tour);
Random random = new Random();
int index1 = random.nextInt(neighbor.size());
int index2 = random.nextInt(neighbor.size());
Collections.swap(neighbor, index1, index2);
return neighbor;
}
private static double calculateTourLength(List<City> tour) {
double length = 0;
for (int i = 0; i < tour.size(); i++) {
City currentCity = tour.get(i);
City nextCity = tour.get((i + 1) % tour.size());
length += currentCity.distanceTo(nextCity);
}
return length;
}
private static double acceptanceProbability(double currentLength, double neighborLength, double temperature) {
if (neighborLength < currentLength) {
return 1.0;
}
return Math.exp((currentLength - neighborLength) / temperature);
}
}
class City {
private String name;
private double x;
private double y;
public City(String name, double x, double y) {
this.name = name;
this.x = x;
this.y = y;
}
public double distanceTo(City other) {
double dx = x - other.x;
double dy = y - other.y;
return Math.sqrt(dx * dx + dy * dy);
}
@Override
public String toString() {
return name;
}
}