問題はこちらです
この問題は典型的なbitDPで解けます。
以下の解説は都市を0-indexで扱うため、例えば都市1->都市0としています。
ここで、S := 訪れた都市の集合。2進数に変換したとき 1 の都市を訪れている と定義します。
例えば、のときは下から0番目と1番目が 1 なので、都市0と都市1を訪れたことになります。
この集合Sを使って、dpテーブルは以下のように定義できます。
dp[S][v] := 訪れた都市の集合が S で最後に訪れた都市が v であるときの最小コスト
遷移は集合 S に対し、まだ訪れていない都市 v と最後に訪れた都市 u を決めると、以下のようになります。
dp[S|(1<<v)][v] = min(dp[S|(1<<v)][v], dp[S][u]+都市 u から都市 v へのコスト)
S|(1<<v) はSに新たに下から v 番目を 1 にしたものを表します。
例えば、S = 4 = のとき v = 1 とすると、4|(1<<1) は となり、新たに都市 1 を訪れたことになります。
この遷移を適切な v と u を選んで行うと、都市0 から全ての都市を1度通って各都市へ移動する最小コストが求められます。
最終的に、(都市0 から各都市へ移動する最小コスト + 最後に各都市から都市0へ戻るコスト)の最小値が答えになります。
わかりにくい解説になってしまいましたが、コードを見て少しでも理解していただけると嬉しいです。
N = int(input()) P = list() for _ in range(N): x,y,z = map(int, input().split()) P.append((x,y,z)) POW = pow(2,N) dp = [[inf]*(N+1) for _ in range(POW)] dp[1][0] = 0 # 都市1からスタート for S in range(POW): for v in range(N): # 次訪れる点 if (S>>v)&1==1: continue # v を既に訪れている場合 for u in range(N): # 最後に訪れた点 if (S>>u)&1==0 and S!=0: continue # u をまだ訪れていない場合(まだ訪れていない頂点からは遷移できない) dp[S|(1<<v)][v] = min(dp[S|(1<<v)][v], dp[S][u]+abs(P[v][0]-P[u][0])+abs(P[v][1]-P[u][1])+max(0,P[v][2]-P[u][2])) ans = inf for v in range(N): ans = min(ans, dp[POW-1][v]+abs(P[0][0]-P[v][0])+abs(P[0][1]-P[v][1])+max(0,P[0][2]-P[v][2])) print(ans)