์ด ๋ฌธ์„œ์˜ ์›๋ณธ์€ ์™ธ๋ถ€ ์œ„ํ‚ค์—์„œ ๊ฐ€์ ธ์™”์Šต๋‹ˆ๋‹ค.
TSP์—์„œ ๋„˜์–ด์˜ด
1. ๊ฐœ์š”2. ๋ฌธ์ œ์˜ ์ •์˜3. ๋ฌธ์ œ์˜ ํ•ด๊ฒฐ
3.1. ๋™์  ๊ณ„ํš์œผ๋กœ ํ’€๊ธฐ3.2. ๋ถ„๊ธฐ ํ•œ์ •์œผ๋กœ ํ’€๊ธฐ

1. ๊ฐœ์š”[ํŽธ์ง‘]

์™ธํŒ์› ์ˆœํšŒ ๋ฌธ์ œ (Traveling Salesperson Problem)๋Š” ์กฐํ•ฉ ์ตœ์ ํ™” ๋ฌธ์ œ์˜ ์ผ์ข…์œผ๋กœ, NP-๋‚œํ•ด ์ง‘ํ•ฉ์— ์†ํ•˜๊ธฐ ๋•Œ๋ฌธ์— ๊ณ„์‚ฐ ์ด๋ก ์—์„œ ํ•ด๋ฅผ ๊ตฌํ•˜๊ธฐ ์–ด๋ ค์šด ๋ฌธ์ œ์˜ ๋Œ€ํ‘œ์ ์ธ ์‚ฌ๋ก€๋กœ ๋งŽ์ด ๋‹ค๋ฃฌ๋‹ค.

์™ธํŒ์› ๋ฌธ์ œ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์ด ์„ค๋ช…ํ•  ์ˆ˜ ์žˆ๋‹ค. ์–ด๋–ค ์™ธํŒ์›์ด n๊ฐœ์˜ ๋„์‹œ๋ฅผ ๋ฐฉ๋ฌธํ•  ๊ณ„ํš์„ ์ˆ˜๋ฆฝํ•˜๊ณ  ์žˆ๋‹ค๊ณ  ๊ฐ€์ •ํ•˜์ž. ๊ฐ ๋„์‹œ๋Š” ๋‹ค๋ฅธ ๋ชจ๋“  ๋„์‹œ์™€ ๋„๋กœ๋กœ ์—ฐ๊ฒฐ๋˜์–ด ์žˆ๋‹ค. ์ถœ์žฅ ๋น„์šฉ์„ ์ตœ์†Œ๋กœ ์ค„์ด๊ธฐ ์œ„ํ•˜์—ฌ ์™ธํŒ์›์ด ๊ฑฐ์ฃผํ•˜๊ณ  ์žˆ๋Š” ๋„์‹œ์—์„œ ๊ฐ ๋„์‹œ๋ฅผ ํ•œ ๋ฒˆ์”ฉ๋งŒ ๋ฐฉ๋ฌธํ•˜๊ณ  ๋‹ค์‹œ ์ถœ๋ฐœํ•œ ๋„์‹œ๋กœ ๋Œ์•„์˜ค๋Š” ๊ฐ€์žฅ ์ตœ์†Œ ๋น„์šฉ์˜ ์ผ์ฃผ์—ฌํ–‰ ๊ฒฝ๋กœ๋ฅผ ์ฐพ๊ณ ์ž ํ•œ๋‹ค.


<ํŒŒ์ด์ฌ ์•Œ๊ณ ๋ฆฌ์ฆ˜ ์ธํ„ฐ๋ทฐ> p.320, ์ฑ…๋งŒ, 2020

๊ทธ๋ฆผ๊ณผ ๊ฐ™์ด ๊ฐ ๋„์‹œ์˜ ์œ„์น˜๊ฐ€ ํ‘œ์‹œ๋œ ๋ฏธ๊ตญ ์ง€๋„๊ฐ€ ์žˆ๋‹ค. ๊ฐ ๋„์‹œ๋ฅผ ํ•œ ๋ฒˆ์”ฉ ๋ฐฉ๋ฌธํ•œ๋‹ค๊ณ  ํ–ˆ์„ ๋•Œ, ์–ด๋–ค ์ˆœ์„œ๋กœ ๋ฐฉ๋ฌธํ•ด์•ผ ๊ฐ€์žฅ ์งง์€ ๊ฑฐ๋ฆฌ๊ฐ€ ๋ ๊นŒ?๋งŒ์•ฝ ๋„์‹œ๊ฐ€ 20๊ฐœ๋ผ๊ณ  ํ•  ๋•Œ ์ด ๋ฌธ์ œ์˜ ์ •๋‹ต์„ ์ฐพ๊ธฐ ์œ„ํ•ด ๋‹ค๋…€์•ผ ํ•˜๋Š” ์ด ๊ฒฝ๋กœ์˜ ์ˆ˜๋Š” ๋‹ค. ์ด ๊ฐ’์€ ์–ผ๋งˆ๋‚˜ ๋ ๊นŒ? ์ด๋‹ค. ๊ทธ๋Ÿฌ๋‹ˆ๊นŒ ์•ฝ 240๊ฒฝ ๋ฒˆ์˜ ๊ฒฝ๋กœ๋ฅผ ๋‹ค๋…€๋ด์•ผ ๊ฐ€์žฅ ์งง์€ ๊ฒฝ๋กœ๋ฅผ ์ฐพ์„ ์ˆ˜ ์žˆ๋‹ค. ๋ฌธ์ œ๋Š” ๋‹จ์ˆœํ•˜์ง€๋งŒ ์ •๋‹ต์€ ์‹ค๋กœ ์—„์ฒญ๋‚˜๋‹ค.

2. ๋ฌธ์ œ์˜ ์ •์˜[ํŽธ์ง‘]

์™ธํŒ์› ์ˆœํšŒ ๋ฌธ์ œ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์ด ๊ทธ๋ž˜ํ”„ ์ด๋ก ์˜ ์šฉ์–ด๋กœ ์—„๋ฐ€ํ•˜๊ฒŒ ์ •์˜ํ•  ์ˆ˜ ์žˆ๋‹ค.

์ฃผ์–ด์ง„ ์™„์ „ ๊ทธ๋ž˜ํ”„ G=(V, E)๊ฐ€, ์—ฐ๊ฒฐ๋˜์–ด ์žˆ๊ณ (connected) ๊ฐ€์ค‘์น˜๊ฐ€ ์žˆ๋Š”(weighted) ์™„์ „ํ•œ(complete) ๊ทธ๋ž˜ํ”„๋ผ๊ณ  ๊ฐ€์ •ํ•˜์ž. ์ด ๊ทธ๋ž˜ํ”„์—์„œ ์ถœ๋ฐœ ์ •์ ์—์„œ ๋‹ค๋ฅธ ๋ชจ๋“  ์ •์ ๋“ค์„ ๋ฐฉ๋ฌธํ•˜๊ณ  ์›๋ž˜์˜ ์ถœ๋ฐœ ์ •์ ์œผ๋กœ ๋˜๋Œ์•„ ์˜ค๋Š” ์ˆœํ™˜ ๊ฒฝ๋กœ๋“ค ์ค‘์—์„œ ๊ฐ€์ค‘์น˜์˜ ํ•ฉ์ด ์ตœ์†Œ๊ฐ€ ๋˜๋Š” ์ˆœํ™˜ ๊ฒฝ๋กœ๋ฅผ ์ฐพ์•„๋ผ.

3. ๋ฌธ์ œ์˜ ํ•ด๊ฒฐ[ํŽธ์ง‘]

์™ธํŒ์› ์ˆœํšŒ ๋ฌธ์ œ๋Š” NP-๋‚œํ•ด ์ง‘ํ•ฉ์— ์†ํ•˜๋Š” ๋ฌธ์ œ๋ผ๋Š” ๊ฒƒ์ด ์ฆ๋ช…๋˜์—ˆ๋‹ค. ๋‹คํ•ญ ์‹œ๊ฐ„์— ์ด ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•  ์ˆ˜ ์žˆ๋Š” ํ•ด๊ฒฐ์ฑ…์„ ์•„๋ฌด๋„ ์ฐพ์ง€ ๋ชปํ–ˆ์œผ๋ฉฐ, ๋‹คํ•ญ ์‹œ๊ฐ„์— ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜์ง€ ๋ชปํ•œ๋‹ค๋Š” ๊ฒƒ๋„ ์•„๋ฌด๋„ ์ฆ๋ช…ํ•˜์ง€ ๋ชปํ–ˆ๋‹ค. ๊ทธ๋ž˜์„œ ๋‚œํ•ดํ•˜๋‹ค๊ณ  ํ•˜๋Š” ๊ฒƒ์ด๋‹ค.

3.1. ๋™์  ๊ณ„ํš์œผ๋กœ ํ’€๊ธฐ[ํŽธ์ง‘]

์™ธํŒ์› ์ˆœํšŒ ๋ฌธ์ œ์˜ ์ตœ์ ํ•ด๋Š” ๋™์  ๊ณ„ํš(Dynamic Programming)์œผ๋กœ ์ง€์ˆ˜ ์‹œ๊ฐ„์— ํ’€ ์ˆ˜ ์žˆ๋‹ค. ๋‹ค์Œ์€ ๋™์  ๊ณ„ํš์œผ๋กœ ์™ธํŒ์› ์ˆœํšŒ ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜๋Š” ํŒŒ์ด์ฌ ์†Œ์Šค ์ฝ”๋“œ์ด๋‹ค.
def travel (W):
    n = len(W) - 1
    size = 2 ** (n - 1)
    D = [[0] * size for _ in range(n + 1)]
    P = [[0] * size for _ in range(n + 1)]
    for i in range(2, n + 1):
        D[i][0] = W[i][1]
    for k in range(1, n - 1):
        for A in range(1, size):
            if (count(A, n) == k):
                for i in range(2, n + 1):
                    if (not isIn(i, A)):
                        D[i][A], P[i][A] = minimum(W, D, i, A)
    A = size - 1
    D[1][A], P[1][A] = minimum(W, D, 1, A)
    return D, P

def minimum (W, D, i, A):
    minValue = INF
    minJ = 1
    n = len(W) - 1
    for j in range(2, n + 1):
        if (isIn(j, A)):
            m = W[i][j] + D[j][diff(A, j)]
            if (minValue > m):
                minValue = m
                minJ = j
    return minValue, minJ
์œ„ ํ’€์ด๋ฒ•์— ๋Œ€ํ•œ ์ž์„ธํ•œ ํ•ด์„ค๊ณผ ์†Œ์Šค ์ฝ”๋“œ์— ๋Œ€ํ•œ ์„ค๋ช…์€ ์ด ์˜์ƒ์„ ์ฐธ๊ณ ํ•˜๋ฉด ๋œ๋‹ค. [1]

3.2. ๋ถ„๊ธฐ ํ•œ์ •์œผ๋กœ ํ’€๊ธฐ[ํŽธ์ง‘]

์™ธํŒ์› ์ˆœํšŒ ๋ฌธ์ œ์˜ ์ตœ์ ํ•ด๋Š” ๋ถ„๊ธฐ ํ•œ์ •(Branch-and-Bound)์œผ๋กœ ์ง€์ˆ˜ ์‹œ๊ฐ„์— ํ’€ ์ˆ˜ ์žˆ๋‹ค. ๋‹ค์Œ์€ ๋™์  ๊ณ„ํš์œผ๋กœ ์™ธํŒ์› ์ˆœํšŒ ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜๋Š” ํŒŒ์ด์ฌ ์†Œ์Šค ์ฝ”๋“œ์ด๋‹ค.
def travel2 (W):
    global minlength, opttour
    n = len(W) - 1
    PQ = PriorityQueue()
    v = SSTNode(0)
    v.path = [1]
    v.bound = bound(v, W)
    minlength = INF
    PQ.put((v.bound, v))
    while (not PQ.empty()):
        v = PQ.get()[1]
        if (v.bound < minlength):
            for i in range(2, n + 1):
                if (v.contains(i)): 
                    continue
                u = SSTNode(v.level + 1)
                u.path = v.path[:]
                u.path.append(i)
                if (u.level == n - 2):
                    for k in range(2, n + 1):
                        if (not u.contains(k)):
                            u.path.append(k)
                    u.path.append(1)
                    if (length(u.path, W) < minlength):
                        minlength = length(u.path, W)
                        opttour = u.path[:]
                else:
                    u.bound = bound(u, W)
                    if (u.bound < minlength):
                        PQ.put((u.bound, u))

def bound(v, W):
    n = len(W) - 1
    total = length(v.path, W)
    for i in range(1, n + 1):
        if (hasOutgoing(i, v.path)):
            continue
        min = INF
        for j in range(1, n + 1):
            if (i == j): continue
            if (hasIncoming(j, v.path)): continue
            if (j == 1 and i == v.path[len(v.path) - 1]): continue
            if (min > W[i][j]): min = W[i][j]
        total += min
    return total
์œ„ ํ’€์ด๋ฒ•์— ๋Œ€ํ•œ ์ž์„ธํ•œ ํ•ด์„ค๊ณผ ์†Œ์Šค ์ฝ”๋“œ์— ๋Œ€ํ•œ ์„ค๋ช…์€ ์ด ์˜์ƒ์„ ์ฐธ๊ณ ํ•˜๋ฉด ๋œ๋‹ค. [2]