首页 > 代码库 > 状态压缩动态规划 -- 旅行商问题

状态压缩动态规划 -- 旅行商问题

旅行商问题:

N个点(N<16)的带权有向图D,求一条路径,使得这条路经过每个点恰好一次,

并且路径上边的权值和最小(或者最大),或者求一条具有这样性质的回路。



状态压缩:

将二进制表示十进制数N的点集,比如:

10 = 0000000000001010 代表第1和3个点已经路过

18 = 0000000000010010 代表第1和4个点已经路过

一个整数就是一个点集,

dp_arr[binary][to_]代表经过点集 binary 中,当前终点为to_,

且路径最短的值,若该状态不存在就是INF



状态转移:

单点集合:状态存在dp_arr[1<<to_][to_] = 0;否则无穷大.

非单点集合:

dp_arr[binary][to] = min( dp_arr[from_bin][from_] + graph[from_][to] )

from_为 from_ 与 to 右边相连,且dp_arr[from_bin][from_] 状态存在,

且 dp_arr[from_bin][from_] 中的 from_bin 尚未包含 to 点信息的一系列点,状态不存在就为INF



最后结果:

min( dp_arr[( 1<<n ) – 1][to_] ) ( 0 <= to_ < N )



python:

INF = 1 << 10

graph = [
    [0, 2, INF, 3],
    [INF, 0, 6, 1],
    [INF, 2, 0, 4],
    [5, 1, 3, 0]
]

state_list = []
citys = 4

dp_arr = [ [ INF for i in xrange( citys ) ] for j in xrange( 1 << citys ) ]


class State:
    def __init__( self, binary = None, end = None ):
        self.binary = binary
        self.end    = end
        

def dp():
    for to_ in range( citys ):
        binary = 1 << to_
        end    = to_
        dp_arr[binary][end] = 0
        state_list.append( State( binary, end ) )

    while len( state_list ):
        pre      = state_list.pop()
        from_bin = pre.binary
        from_    = pre.end
        
        for to_ in xrange( citys ):
            binary = 1 << to_
            
            if binary & from_bin or graph[from_][to_] is INF:
                continue
            
            binary    |= from_bin
            next_state = State( binary, to_ )
            distance   = dp_arr[from_bin][from_] + graph[from_][to_]
            state_list.append( next_state )
            dp_arr[binary][to_] = min( dp_arr[binary][to_], distance )
           

if __name__ == '__main__':
    dp()
    ans = min( [ dp_arr[( 1 << citys ) - 1][to_] for to_ in xrange( citys ) ] )
    print ans