启发式算法-蚁群算法
蚁群算法是模拟蚂蚁觅食行为的仿生优化算法,原理是信息素的正反馈机制,蚂蚁通过释放信息素来引导同伴找到最短路径。把问题的元素抽象为多条路径,每次迭代时为每只蚂蚁构建一个解决方案,该解决方案对应一条完整的路径,每次迭代后对所有路径上的信息素按一定比例模拟自然蒸发,避免局部最优,然后找出当前的最优路径进行信息素增强,在之后的迭代中蚂蚁就会倾向于选择信息素浓度高的路径,经过多次迭代后,找出全局的最优路径。该算法通常用于解决旅行商等NP难问题,算法性能依赖参数(如信息素重要因子 α、启发式因子 β、挥发率 ρ 等),结果难以预测,有一定的玄学。
算法流程
集合覆盖问题
给定一个全集U和若干子集S1, S2, …, Sn,找到最少数量的子集,使得它们的并集等于U。例如:
全集 U = {1, 2, 3, 4, 5}
子集 S1 = {1, 3}, S2 = {2, 3}, S3 = {3, 4}, S4 = {1, 4, 5}
最优解:[S1, S3] 能覆盖所有元素的最小子集数量为2。
蚁群算法代码
import java.util.*;public class AcoSetCover {// 定义全集和子集static Set<Integer> universe = new HashSet<>(Arrays.asList(1, 2, 3, 4,5));static List<Set<Integer>> subsets = Arrays.asList(new HashSet<>(Arrays.asList(1, 3)),new HashSet<>(Arrays.asList(2, 3)),new HashSet<>(Arrays.asList(3, 4)),new HashSet<>(Arrays.asList(1, 4, 5)));static int numSubsets = subsets.size();// 算法参数static int m = 10; // 蚂蚁数量static int maxIter = 10000; // 最大迭代次数static double alpha = 1.0; // 信息素重要因子static double beta = 2.0; // 启发式因子static double rho = 0.1; // 信息素挥发率static double Q = 1.0; // 信息素强度static double[] pheromone; // 子集的信息素public static void main(String[] args) {initializePheromone();List<Integer> bestSolution = null;int bestSize = Integer.MAX_VALUE;for (int iter = 0; iter < maxIter; iter++) {List<List<Integer>> antSolutions = new ArrayList<>();for (int ant = 0; ant < m; ant++) {List<Integer> solution = constructSolution();antSolutions.add(solution);if (solution.size() < bestSize) {bestSize = solution.size();bestSolution = new ArrayList<>(solution);}}updatePheromone(antSolutions);}System.out.println("全集: "+universe);System.out.println("子集: "+subsets);System.out.println("最优解子集下标: " + bestSolution);for(int i:bestSolution){System.out.println(subsets.get(i));}}// 初始化信息素static void initializePheromone() {pheromone = new double[numSubsets];Arrays.fill(pheromone, 1.0); // 初始信息素为1}// 蚂蚁构建解static List<Integer> constructSolution() {Set<Integer> covered = new HashSet<>();List<Integer> solution = new ArrayList<>();List<Integer> candidates = new ArrayList<>();while (!covered.equals(universe)) {candidates.clear();for (int i = 0; i < numSubsets; i++) {if (!solution.contains(i) && !Collections.disjoint(subsets.get(i), universe)) {Set<Integer> subset = subsets.get(i);if (!covered.containsAll(subset)) {candidates.add(i);}}}if (candidates.isEmpty()) break;// 计算选择概率double[] probabilities = new double[candidates.size()];double total = 0.0;for (int i = 0; i < candidates.size(); i++) {int subsetIdx = candidates.get(i);double heuristic = (double) (subsets.get(subsetIdx).size() - covered.size()) / subsets.get(subsetIdx).size();probabilities[i] = Math.pow(pheromone[subsetIdx], alpha) * Math.pow(heuristic, beta);total += probabilities[i];}// 轮盘赌选择double rand = Math.random() * total;double cumulative = 0.0;int selected = -1;for (int i = 0; i < candidates.size(); i++) {cumulative += probabilities[i];if (cumulative >= rand) {selected = candidates.get(i);break;}}// 更新覆盖集和解solution.add(selected);covered.addAll(subsets.get(selected));}return solution;}// 更新信息素static void updatePheromone(List<List<Integer>> antSolutions) {// 信息素挥发for (int i = 0; i < numSubsets; i++) {pheromone[i] *= (1 - rho);}// 蚂蚁释放信息素for (List<Integer> solution : antSolutions) {double delta = Q / solution.size();for (int subsetIdx : solution) {pheromone[subsetIdx] += delta;}}}
}
该算法还可以用于解决覆盖设计问题