我決定學習模擬退火與攻擊this problem的新方法。它主要是詢問如何用-1,0或1填充網格,以便每行和列的和是唯一的。作爲測試的情況下,我用了一個6x6的網格中,這肯定是有由Neil給出最佳的解決方案:模擬退火不返回(一)最優解
1 1 1 1 1 1 6
1 1 1 1 1 -1 4
1 1 1 1 -1 -1 2
1 1 0 -1 -1 -1 -1
1 0 -1 -1 -1 -1 -3
0 -1 -1 -1 -1 -1 -5
5 3 1 0 -2 -4
我的代碼通常不會達到最佳的情況下,大多數運行,甚至返回錯誤網格成本(old_cost
應匹配count_conflict(grid)
)。我的參數是否設置錯誤?是否錯誤地實施了,或者可能是模擬退火不是一種可行的方法?
import random
from math import exp
G_SIZE = 6
grid = [[1]*G_SIZE for i in range(G_SIZE)]
def count_conflict(grid):
cnt = [0]*(2*G_SIZE+1)
conflicts = 0
for row in grid:
cnt[sum(row)] += 1
for col in zip(*grid):
cnt[sum(col)] += 1
#print(cnt)
for c in cnt:
if c == 0: conflicts += 1
if c > 1: conflicts += c-1
return conflicts
def neighbor(grid):
new_grid = grid[:]
i = random.choice(range(G_SIZE))
j = random.choice(range(G_SIZE))
new_cells = [-1, 0, 1]
new_cells.remove(new_grid[i][j])
new_grid[i][j] = random.choice(new_cells)
return new_grid
def acceptance_probability(old_cost, new_cost, T):
if new_cost < old_cost: return 1.0
return exp(-(new_cost - old_cost)/T)
# Initial guess
for i in range(1, G_SIZE):
for j in range(0, i):
grid[i][j] = -1
#print(grid)
old_cost = count_conflict(grid)
T = 10.0
T_min = 0.1
alpha = 0.99
while T > T_min:
for i in range(1000):
new_sol = neighbor(grid)
new_cost = count_conflict(new_sol)
ap = acceptance_probability(old_cost, new_cost, T)
print(old_cost, new_cost, ap, T)
if ap > random.random():
grid = new_sol
old_cost = new_cost
T *= alpha
for row in grid:
print(row)
print(count_conflict(grid))
不知何故,我認爲基礎問題應該在數學問題板上發佈,因爲它似乎可以將這個問題轉化爲一組具有多個變量的鏈接方程,這些變量轉換爲矩陣計算。 – DainDwarf
我很確定SA不提供任何保證找到全局最小值。擲骰子的次數越多,在某些情況下(可能)你更有可能找到它。玩你的冷靜配置文件。至少在一開始,這是你必須進行半手動操作的事情。你能比較你的例程與已知的東西 - 爲什麼不與'scipy.optimize.anneal'並行運行並比較行爲。 – uhoh
@uhoh我已經擺弄了一些參數,但程序通常停止了短短的預期目標。由於模擬退火與N皇后問題一起工作,我希望它能在這裏工作。 – qwr