← Назад к алгоритмам поиска

Имитация отжига

Метаэвристический алгоритм для решения задач оптимизации

🐍 Python
import random
import math

def ok(A):
    z = 0
    for i in range(n):
        for j in range(i + 1, n):
            if abs(i - j) == abs(A[i] - A[j]):
                z += 1
    return z

n = int(input())
t = 10000.0
A = list(range(1, n + 1))
random.shuffle(A)
ans = ok(A)
C = list(A)
z = ans

while z > 0:
    i = random.randint(0, n - 1)
    j = random.randint(0, n - 1)
    if i == j:
        continue
    A[i], A[j] = A[j], A[i]
    val = ok(A)
    if val < ans or random.random() < math.exp((ans - val) / t):
        ans = val
        if val == 0:
            C = list(A)
            z = val
            break
    else:
        A[i], A[j] = A[j], A[i]
    t *= 0.99

print(*C)
⚙️ C++
#include <bits/stdc++.h>
using namespace std;

int ok(const vector<int>& A, int n) {
    int z = 0;
    for (int i = 0; i < n; ++i) {
        for (int j = i + 1; j < n; ++j) {
            if (abs(i - j) == abs(A[i] - A[j])) {
                z++;
            }
        }
    }
    return z;
}

int main() {
    srand(time(0));
    int n;
    cin >> n;
    
    double t = 10000.0;
    vector<int> A(n);
    for (int i = 0; i < n; ++i) {
        A[i] = i + 1;
    }
    
    random_shuffle(A.begin(), A.end());
    
    int ans = ok(A, n);
    vector<int> C = A;
    int z = ans;
    
    while (z > 0) {
        int i = rand() % n;
        int j = rand() % n;
        if (i == j) continue;
        
        swap(A[i], A[j]);
        int val = ok(A, n);
        
        double random_value = (double)rand() / RAND_MAX;
        if (val < ans || random_value < exp((ans - val) / t)) {
            ans = val;
            if (val == 0) {
                C = A;
                z = val;
                break;
            }
        } else {
            swap(A[i], A[j]);
        }
        
        t *= 0.99;
    }
    
    for (int num : C) {
        cout << num << " ";
    }
    cout << endl;
    
    return 0;
}

Как работает имитация отжига?

Имитация отжига (Simulated Annealing) — это вероятностный алгоритм глобальной оптимизации, вдохновлённый процессом отжига в металлургии. Он позволяет находить приближённые решения сложных задач оптимизации.

Основная идея

В отличие от жадных алгоритмов, которые могут застрять в локальном минимуме, имитация отжига с некоторой вероятностью принимает ухудшающие решения, что позволяет "выпрыгнуть" из локальных оптимумов и найти глобальный минимум.

Параметры алгоритма

Правило принятия решения

Новое решение принимается, если:

Задача о ферзях

В данной реализации алгоритм ищет расстановку n ферзей на доске n×n так, чтобы они не атаковали друг друга. Оптимальное решение — когда количество конфликтующих пар равно 0.

Временная сложность: зависит от количества итераций (обычно O(n² × итераций)).

Формат ввода и вывода

Ввод:

Вывод:

Пример ввода:

8

Вывод (пример): 5 1 8 4 2 7 3 6

Это одна из возможных расстановок 8 ферзей, где никакие два не атакуют друг друга.

Примечание: алгоритм вероятностный, поэтому при разных запусках могут получаться разные решения. Для n=8 решение всегда существует.

Попробовать имитацию отжига онлайн

Введите количество ферзей (размер доски):

Результат появится здесь...