公式

E - 展望台への登山 / Climbing to the Observation Deck 解説 by harurun4635


立ち寄るチェックポイントが狭義単調増加なことに注目すれば、「前の状態」に戻ることはないです。つまり、遷移は DAG ですから DP を考えてみましょう。必要な状態は何でしょうか?

  • 今どの頂点にいるか
  • 今何個の頂点を訪問しているか(最小個数の条件のため)
  • 今各タイプのチェックポイントの訪問数の偶奇(地形バランスの条件)

の \(3\) つがあれば、十分です。

このとき、状態数は \(O(N \times N \times 2^M)\) です。そして、遷移は \(O(N)\) 通りですから、この DP を素直に書けば間に合うことがわかります。


実装例

特に PyPy 等の言語では多次元配列が遅くなる傾向があります注意してください。(今回の問題であれば、適切に書けば間に合います)

たとえば「 今何個の頂点を訪問しているか」等の key は next DP にすれば DP テーブルで陽にもつ必要はないです。実装例では、特にそのようなことはしていませんが、メモリ制限の厳しい問題で必要になることもあるテクニックです。

n, m, k = [int(x) for x in input().split()]
t = [-1] + [int(x)-1 for x in input().split()]

c = []
for i in range(n + 1):
    c.append([0] * (i + 1) + [int(x) for x in input().split()])

inf = 1 << 60
dp = [[[inf] * (1 << m) for j in range(k + 1)] for i in range(n + 2)]
dp[0][0][0] = 0

for i in range(n + 2):
    for j in range(k + 1):
        for bit in range(1 << m):
            for ni in range(i + 1, n + 2):
                if ni == n + 1:
                    dp[ni][j][bit] = min(dp[ni][j][bit], dp[i][j][bit] + c[i][ni])
                else:
                    dp[ni][min(j+1, k)][bit ^ (1 << t[ni])] = min(dp[ni][min(j+1, k)][bit ^ (1 << t[ni])], dp[i][j][bit] + c[i][ni])

if dp[n+1][k][0] == inf:
    print(-1)
else:
    print(dp[n+1][k][0]) 

投稿日時:
最終更新: