import math, time, random
from itertools import permutations
def rot(m, k):
mlen = len(m)
if k == 0: return m
return [[m[(i-k)%mlen][(j-k)%mlen] for j in range(mlen)] for i in range(mlen)]
def cs(m, ker):
ml, kl = len(m), len(ker)
res = 0
for i in range(ml - kl + 1):
for ki in range(kl):
res += m[i+ki][i+ki] * ker[ki][ki]
return res
def tsp(b52, s, e, k):
st = time.time()
n = len(b52)
d = [[0]*n for _ in range(n)]
for i in range(n):
x1, y1 = b52[i]
for j in range(i+1, n):
x2, y2 = b52[j]
dist = int(math.hypot(x1-x2, y1-y2))
d[i][j] = d[j][i] = dist
sidx = []
for i in range(n):
r = [(d[i][j], j) for j in range(n) if j != i]
r.sort()
sidx.append([idx for _, idx in r])
wm = []
for c in range(n):
o = sidx[c]
m = n-1
mat = [[0]*m for _ in range(m)]
for i in range(m):
for j in range(m):
if i != j: mat[i][j] = 1 if o[i] > o[j] else 0
wm.append(mat)
ce = [[set() for _ in range(n)] for __ in range(n)]
cf = [
\[0.5, -0.5\], \[-0.5, 0.5\]
] + [
\[0.5, -0.5, 0.5\], \[-0.5, 0.5, -0.5\], \[0.5, -0.5, 0.5\]
]
for fl in cf:
ns = []
for c in range(n):
mat = wm[c]
sc = [(cs(rot(mat, r), fl), r) for r in range(n-1)]
sc.sort(reverse=True)
ns.append(sc[:k])
for i in range(n):
for sc, r in ns[i]:
j = sidx[i][r]
ce[i][j].add(r)
if len(ce[i][j]) > k:
ce[i][j] = set(list(ce[i][j])[:k])
ec = [[[] for _ in range(n)] for __ in range(n)]
for i in range(n):
if i != s:
for j in range(n):
if i != j and ce[i][j]:
for r in sorted(list(ce[i][j]))[:k]:
ec[i][j].append(sidx[i][r])
p = [s]
v = [False]*n
v[s] = True
for _ in range(n-1):
u = p[-1]
nn = [vb for vl in ec[u] for vb in vl if vb and not v[vb]]
if not nn:
nn = [vb for vb in range(n) if not v[vb]]
p.append(nn[0])
v[p[-1]] = True
p.append(e)
def cpd(pth):
return sum(d[pth[i]][pth[i+1]] for i in range(len(pth)-1))
bd = cpd(p)
imp = True
mx = 1000
cnt = 0
while imp and cnt < mx:
imp = False
cnt += 1
for i in range(1, len(p)-2):
for j in range(i+1, len(p)-1):
dt = d[p[i-1]][p[j]] + d[p[i]][p[j+1]] - d[p[i-1]][p[i]] - d[p[j]][p[j+1]]
if dt < 0:
p[i:j+1] = p[i:j+1][::-1]
bd += dt
imp = True
return bd, p, time.time()-st,n
def c(p, e, D):
return sum(D[p[i]][p[i+1]] for i in range(len(p)-1)) + D[p[-1]][e]
def g(k, ei):
el, ci = len(ei), 0
eg = {u: [] for u in range(k)}
for (u, v), i in ei.items():
eg[u].append(i)
ud = set()
for ids in eg.values():
for i in ids:
while True:
pb = (i << 1) | random.getrandbits(1)
if pb not in ud:
ud.add(pb)
ci |= (pb & 1) << i
break
if k >= 2:
u1, u2 = random.sample(range(k), 2)
df = len(eg[u1]) - len(eg[u2])
if abs(df) <= math.isqrt(k):
elc = int(abs(math.sin(k) * df))
if elc > 0:
src = u2 if df > 0 else u1
ai = random.sample(eg[src], min(elc, len(eg[src])))
ci |= sum(1 << i for i in ai) if df > 0 else ~sum(1 << i for i in ai)
ec = {}
ci %= 1 << el
for (u, v), i in ei.items():
ec[(u, v)] = ec[(v, u)] = (ci >> i) & 1
return ec
def o(p, D):
imp = True
while imp:
imp = False
for i in range(1, len(p) - 2):
for k in range(i + 2, len(p)):
if D[p[i-1]][p[i]] + D[p[k-1]][p[k]] > D[p[i-1]][p[k-1]] + D[p[i]][p[k]]:
p[i:k] = p[i:k][::-1]
imp = True
return p
berlin52=[(565.0,575.0),(25.0,185.0),(345.0,750.0),(945.0,685.0),(845.0,655.0),(880.0,660.0),(25.0,230.0),(525.0,1000.0),(580.0,1175.0),(650.0,1130.0),(1605.0,620.0),(1220.0,580.0),(1465.0,200.0),(1530.0,5.0),(845.0,680.0),(725.0,370.0),(145.0,665.0),(415.0,635.0),(510.0,875.0),(560.0,365.0),(300.0,465.0),(520.0,585.0),(480.0,415.0),(835.0,625.0),(975.0,580.0),(1215.0,245.0),(1320.0,315.0),(1250.0,400.0),(660.0,180.0),(410.0,250.0),(420.0,555.0),(575.0,665.0),(1150.0,1160.0),(700.0,580.0),(685.0,595.0),(685.0,610.0),(770.0,610.0),(795.0,645.0),(720.0,635.0),(760.0,650.0),(475.0,960.0),(95.0,260.0),(875.0,920.0),(700.0,500.0),(555.0,815.0),(830.0,485.0),(1170.0,65.0),(830.0,610.0),(605.0,625.0),(595.0,360.0),(1340.0,725.0),(1740.0,245.0)]
print("TSP问题求解 - 柏林52个城市")
print("正在计算基础解...")
s=0
se=0
base_dist, base_path, base_time,n = tsp(berlin52, s, se, 1000)
d = [[0]*n for _ in range(n)]
for i in range(n):
x1, y1 = berlin52[i]
for j in range(i+1, n):
x2, y2 = berlin52[j]
d[i][j] = d[j][i] = ((x1 - x2)**2 + (y1 - y2)**2)**0.5
print(f"基础解距离: {base_dist:.2f}, 耗时: {base_time:.4f}s")
print(f"基础路径: {base_path}")
st = time.time()
dt0 = sorted((d[i][0], i) for i in range(1, n))
df0 = sorted((d[0][i], i) for i in range(1, n))
rt0 = {idx: r+1 for r, (_, idx) in enumerate(dt0)}
rf0 = {idx: r+1 for r, (_, idx) in enumerate(df0)}
vn = []
for i in range(1, n):
a, b = rt0[i], rf0[i]
fd = False
for m in range(1, b):
for t in range(1, 3):
if (m * (a**t)) % b == 0:
vn.append(i)
fd = True
break
if fd:break
vn = vn if vn else list(range(1, n))
bp = base_path
bd = base_dist
ei = {}
idx = 0
for i in range(n):
for k in range(i+1, n):
ei[(i, k)] = idx
idx += 1
opt2_cnt = 0
for _ in range(50):
random.seed()
for _ in range(50):
ec = g(n, ei)
random.shuffle(vn)
p = [s] + vn + [se]
gss = [[] for _ in range(2)]
for nd in vn:gss[ec.get((nd % n, (nd + 1) % n), 0)].append(nd)
np = [s]
for gs in gss:
if gs:np.extend(random.sample(gs, len(gs)))
np.append(se)
cd = c(np, se, d)
if cd < bd * 4:
np = o(np, d)
opt2_cnt += 1
cd = c(np, se, d)
if cd < bd:
bd = cd
bp = np
print(f"\n优化后结果:")
print(f"{n}节点 起点:{s} 终点:{se}")
print(f"最优路径: {bp}")
print(f"最优距离: {bd}")
print(f"总时间: {time.time()-st:.2f}s")
print(f"opt2调用次数: {opt2_cnt}")